<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.17">
<title>Spring Boot Admin 参考指南</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
/* Uncomment the following line when using as a custom stylesheet */
/* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */
html{font-family:sans-serif;-webkit-text-size-adjust:100%}
a{background:none}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
b,strong{font-weight:bold}
abbr{font-size:.9em}
abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none}
dfn{font-style:italic}
hr{height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
audio,video{display:inline-block}
audio:not([controls]){display:none;height:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type=checkbox],input[type=radio]{padding:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,::before,::after{box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:0}
p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt{background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.center{margin-left:auto;margin-right:auto}
.stretch{width:100%}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
.clearfix::after,.float-group::after{clear:both}
:not(pre).nobreak{word-wrap:normal}
:not(pre).nowrap{white-space:nowrap}
:not(pre).pre-wrap{white-space:pre-wrap}
:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
pre>code{display:block}
pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menuref{color:#000}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq{word-spacing:-.02em}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
#content{margin-top:1.25em}
#content::before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:hsla(0,0%,100%,.8);line-height:1.44}
#content{margin-bottom:.625em}
.sect1{padding-bottom:.625em}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1{padding-bottom:1.25em}}
.sect1:last-child{padding-bottom:0}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
details{margin-left:1.25rem}
details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent}
details>summary::-webkit-details-marker{display:none}
details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)}
details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)}
details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
.paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
.listingblock>.content{position:relative}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.prettyprint{background:#f7f7f8}
pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
pre.prettyprint li code[data-lang]::before{opacity:1}
pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
table.linenotable td.code{padding-left:.75em}
table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
pre.pygments span.linenos{display:inline-block;margin-right:.75em}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0}
p.tableblock:last-child{margin-bottom:0}
td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere}
td.tableblock>.content>:last-child{margin-bottom:-1.25em}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>*>tr>*{border-width:1px}
table.grid-cols>*>tr>*{border-width:0 1px}
table.grid-rows>*>tr>*{border-width:1px 0}
table.frame-all{border-width:1px}
table.frame-ends{border-width:1px 0}
table.frame-sides{border-width:0 1px}
table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}
table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}
table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0}
table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0}
table.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
ul.unstyled,ol.unstyled{margin-left:0}
li>p:empty:only-child::before{content:"";display:inline-block}
ul.checklist>li>p:first-child{margin-left:-1em}
ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em}
ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
ul.inline>li{margin-left:1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
td.hdlist2{word-wrap:anywhere}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background:#00fafa}
.black{color:#000}
.black-background{background:#000}
.blue{color:#0000bf}
.blue-background{background:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background:#fa00fa}
.gray{color:#606060}
.gray-background{background:#7d7d7d}
.green{color:#006000}
.green-background{background:#007d00}
.lime{color:#00bf00}
.lime-background{background:#00fa00}
.maroon{color:#600000}
.maroon-background{background:#7d0000}
.navy{color:#000060}
.navy-background{background:#00007d}
.olive{color:#606000}
.olive-background{background:#7d7d00}
.purple{color:#600060}
.purple-background{background:#7d007d}
.red{color:#bf0000}
.red-background{background:#fa0000}
.silver{color:#909090}
.silver-background{background:#bcbcbc}
.teal{color:#006060}
.teal-background{background:#007d7d}
.white{color:#bfbfbf}
.white-background{background:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background:#fafa00}
span.icon>.fa{cursor:default}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]::after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt,summary{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@page{margin:1.25cm .75cm}
@media print{*{box-shadow:none!important;text-shadow:none!important}
html{font-size:80%}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]{border-bottom:1px dotted}
abbr[title]::after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#header,#content,#footnotes,#footer{max-width:none}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
@media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem}
.sect1{padding:0!important}
.sect1+.sect1{border:0}
#footer{background:none}
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
/*! Stylesheet for CodeRay to loosely match GitHub themes | MIT License */
pre.CodeRay{background:#f7f7f8}
.CodeRay .line-numbers{border-right:1px solid;opacity:.35;padding:0 .5em 0 0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
.CodeRay span.line-numbers{display:inline-block;margin-right:.75em}
.CodeRay .line-numbers strong{color:#000}
table.CodeRay{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.CodeRay td{vertical-align:top;line-height:inherit}
table.CodeRay td.line-numbers{text-align:right}
table.CodeRay td.code{padding:0 0 0 .75em}
.CodeRay .debug{color:#fff!important;background:navy!important}
.CodeRay .annotation{color:#007}
.CodeRay .attribute-name{color:navy}
.CodeRay .attribute-value{color:#700}
.CodeRay .binary{color:#509}
.CodeRay .comment{color:#998;font-style:italic}
.CodeRay .char{color:#04d}
.CodeRay .char .content{color:#04d}
.CodeRay .char .delimiter{color:#039}
.CodeRay .class{color:#458;font-weight:bold}
.CodeRay .complex{color:#a08}
.CodeRay .constant,.CodeRay .predefined-constant{color:teal}
.CodeRay .color{color:#099}
.CodeRay .class-variable{color:#369}
.CodeRay .decorator{color:#b0b}
.CodeRay .definition{color:#099}
.CodeRay .delimiter{color:#000}
.CodeRay .doc{color:#970}
.CodeRay .doctype{color:#34b}
.CodeRay .doc-string{color:#d42}
.CodeRay .escape{color:#666}
.CodeRay .entity{color:#800}
.CodeRay .error{color:#808}
.CodeRay .exception{color:inherit}
.CodeRay .filename{color:#099}
.CodeRay .function{color:#900;font-weight:bold}
.CodeRay .global-variable{color:teal}
.CodeRay .hex{color:#058}
.CodeRay .integer,.CodeRay .float{color:#099}
.CodeRay .include{color:#555}
.CodeRay .inline{color:#000}
.CodeRay .inline .inline{background:#ccc}
.CodeRay .inline .inline .inline{background:#bbb}
.CodeRay .inline .inline-delimiter{color:#d14}
.CodeRay .inline-delimiter{color:#d14}
.CodeRay .important{color:#555;font-weight:bold}
.CodeRay .interpreted{color:#b2b}
.CodeRay .instance-variable{color:teal}
.CodeRay .label{color:#970}
.CodeRay .local-variable{color:#963}
.CodeRay .octal{color:#40e}
.CodeRay .predefined{color:#369}
.CodeRay .preprocessor{color:#579}
.CodeRay .pseudo-class{color:#555}
.CodeRay .directive{font-weight:bold}
.CodeRay .type{font-weight:bold}
.CodeRay .predefined-type{color:inherit}
.CodeRay .reserved,.CodeRay .keyword{color:#000;font-weight:bold}
.CodeRay .key{color:#808}
.CodeRay .key .delimiter{color:#606}
.CodeRay .key .char{color:#80f}
.CodeRay .value{color:#088}
.CodeRay .regexp .delimiter{color:#808}
.CodeRay .regexp .content{color:#808}
.CodeRay .regexp .modifier{color:#808}
.CodeRay .regexp .char{color:#d14}
.CodeRay .regexp .function{color:#404;font-weight:bold}
.CodeRay .string{color:#d20}
.CodeRay .string .string .string{background:#ffd0d0}
.CodeRay .string .content{color:#d14}
.CodeRay .string .char{color:#d14}
.CodeRay .string .delimiter{color:#d14}
.CodeRay .shell{color:#d14}
.CodeRay .shell .delimiter{color:#d14}
.CodeRay .symbol{color:#990073}
.CodeRay .symbol .content{color:#a60}
.CodeRay .symbol .delimiter{color:#630}
.CodeRay .tag{color:teal}
.CodeRay .tag-special{color:#d70}
.CodeRay .variable{color:#036}
.CodeRay .insert{background:#afa}
.CodeRay .delete{background:#faa}
.CodeRay .change{color:#aaf;background:#007}
.CodeRay .head{color:#f8f;background:#505}
.CodeRay .insert .insert{color:#080}
.CodeRay .delete .delete{color:#800}
.CodeRay .change .change{color:#66f}
.CodeRay .head .head{color:#f4f}
</style>
</head>
<body class="book toc2 toc-left">
<div id="header">
<h1>Spring Boot Admin 参考指南</h1>
<div class="details">
<span id="revnumber">version 2.6.6,</span>
<span id="revdate">08.04.2022</span>
</div>
<div id="toc" class="toc2">
<div id="toctitle">目录</div>
<ul class="sectlevel1">
<li><a href="#_什么是_spring_boot_adminsba">1. 什么是 Spring Boot Admin（SBA）?</a></li>
<li><a href="#getting-started">2. 入门</a>
<ul class="sectlevel2">
<li><a href="#set-up-admin-server">2.1. 配置SBA服务端应用程序</a></li>
<li><a href="#register-client-applications">2.2. 注册客户端应用程序</a>
<ul class="sectlevel3">
<li><a href="#register-clients-via-spring-boot-admin">2.2.1. SBA客户端服务</a></li>
<li><a href="#discover-clients-via-spring-cloud-discovery">2.2.2. Spring Cloud 服务发现</a></li>
<li><a href="#register-python-applications">2.2.3. 使用Pyctuator注册Python应用程序</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#client-applications">3. 客户端应用程序</a>
<ul class="sectlevel2">
<li><a href="#show-version-in-application-list">3.1. 在应用列表中显示版本号</a></li>
<li><a href="#jmx-bean-management">3.2. JMX-Bean的管理</a></li>
<li><a href="#logfile">3.3. 查看日志文件</a></li>
<li><a href="#show-instance-tags">3.4. 显示实例的标签</a></li>
<li><a href="#spring-boot-admin-client">3.5. SBA客户端</a></li>
</ul>
</li>
<li><a href="#spring-boot-admin-server">4. SBA服务端</a>
<ul class="sectlevel2">
<li><a href="#_通过代理访问运行的服务端">4.1. 通过代理访问运行的服务端</a></li>
<li><a href="#_配置项">4.2. 配置项</a></li>
<li><a href="#spring-cloud-discovery-support">4.3. Spring Cloud 服务发现</a>
<ul class="sectlevel3">
<li><a href="#spring-cloud-discovery-static-config">4.3.1. 使用SimpleDiscoveryClient进行静态配置</a></li>
<li><a href="#_其它方式的服务发现客户端">4.3.2. 其它方式的服务发现客户端</a></li>
<li><a href="#_转换服务实例">4.3.3. 转换服务实例</a></li>
<li><a href="#_cloudfoundry">4.3.4. CloudFoundry</a></li>
</ul>
</li>
<li><a href="#clustering-support">4.4. 集群</a></li>
<li><a href="#_消息通知">4.5. 消息通知</a>
<ul class="sectlevel3">
<li><a href="#mail-notifications">4.5.1. 邮件通知</a></li>
<li><a href="#pagerduty-notifications">4.5.2. PagerDuty通知</a></li>
<li><a href="#opsgenie-notifications">4.5.3. OpsGenie通知</a></li>
<li><a href="#hipchat-notifications">4.5.4. Hipchat通知</a></li>
<li><a href="#slack-notifications">4.5.5. Slack通知</a></li>
<li><a href="#letschat-notifications">4.5.6. Let&#8217;s Chat通知</a></li>
<li><a href="#ms-teams-notifications">4.5.7. Microsoft Teams通知</a></li>
<li><a href="#telegram-notifications">4.5.8. Telegram通知</a></li>
<li><a href="#discord-notifications">4.5.9. Discord通知</a></li>
<li><a href="#notification-proxy">4.5.10. 为消息通知配置代理</a></li>
<li><a href="#reminder-notifications">4.5.11. 通知发送程序</a></li>
<li><a href="#filtering-notifications">4.5.12. 过滤通知</a></li>
<li><a href="#DingTalk-notifications">4.5.13. 钉钉通知</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#securing-spring-boot-admin">5. 安全</a>
<ul class="sectlevel2">
<li><a href="#_保护sba服务端的安全">5.1. 保护SBA服务端的安全</a></li>
<li><a href="#_保护客户端默认actuator接口">5.2. 保护客户端默认Actuator接口</a>
<ul class="sectlevel3">
<li><a href="#_sba客户端">5.2.1. SBA客户端</a></li>
<li><a href="#_sba服务端">5.2.2. SBA服务端</a></li>
<li><a href="#_eureka">5.2.3. Eureka</a></li>
<li><a href="#_consul">5.2.4. Consul</a></li>
<li><a href="#_默认actuator接口的csrf保护">5.2.5. 默认Actuator接口的CSRF保护</a></li>
</ul>
</li>
<li><a href="#_使用自定义tls">5.3. 使用自定义TLS</a></li>
</ul>
</li>
<li><a href="#customizing">6. 自定义</a>
<ul class="sectlevel2">
<li><a href="#customizing-notifiers">6.1. 自定义通知器</a></li>
<li><a href="#customizing-headers">6.2. 自定义HTTP请求头</a></li>
<li><a href="#customizing-instance-filter">6.3. 对请求和响应进行拦截</a></li>
<li><a href="#customizing-external-views">6.4. 链接/嵌入外部页面</a></li>
<li><a href="#customizing-custom-views">6.5. 自定义页面</a>
<ul class="sectlevel3">
<li><a href="#customizing-custom-views-top-level">6.5.1. 添加顶级页面</a></li>
<li><a href="#customizing-custom-views-instance">6.5.2. 查看自定义接口</a></li>
</ul>
</li>
<li><a href="#_自定义顶部logo和标题">6.6. 自定义顶部Logo和标题</a></li>
<li><a href="#_自定义登录logo">6.7. 自定义登录Logo</a></li>
<li><a href="#_自定义favicon">6.8. 自定义Favicon</a></li>
<li><a href="#_自定义可用语言">6.9. 自定义可用语言</a></li>
<li><a href="#_显示隐藏页面">6.10. 显示/隐藏页面</a></li>
</ul>
</li>
<li><a href="#monitoring-spring-boot-1.5.x">7. 监听1.5.x版本的Spring Boot</a></li>
<li><a href="#_2_x版本的变化">8. 2.x版本的变化</a>
<ul class="sectlevel2">
<li><a href="#_页面">8.1. 页面</a></li>
<li><a href="#_后端">8.2. 后端</a></li>
<li><a href="#_客户端">8.3. 客户端</a></li>
</ul>
</li>
<li><a href="#faqs">9. 常见问题</a></li>
</ul>
</div>
</div>
<div id="content">
<div class="sect1">
<h2 id="_什么是_spring_boot_adminsba"><a class="anchor" href="#_什么是_spring_boot_adminsba"></a><a class="link" href="#_什么是_spring_boot_adminsba">1. 什么是 Spring Boot Admin（SBA）?</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Spring Boot Admin 是 codecentric 公司开发的一款开源社区项目，目标是让用户更方便的管理以及监控
<a href="http://projects.spring.io/spring-boot/">Spring Boot</a> <sup>&#174;</sup>
应用。
应用可以通过我们的Spring Boot Admin客户端（通过HTTP的方式）或者使用Spring Cloud <sup>&#174;</sup>（比如Eureka，consul的方式）注册。
而前端UI则是使用Vue.js，基于Spring Boot Actuator默认接口开发的。</p>
</div>
<div class="paragraph">
<p>针对Python应用可以使用 <a href="https://github.com/SolarEdgeTech/pyctuator">Pyctuator</a> 来进行支持。</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="getting-started"><a class="anchor" href="#getting-started"></a><a class="link" href="#getting-started">2. 入门</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="set-up-admin-server"><a class="anchor" href="#set-up-admin-server"></a><a class="link" href="#set-up-admin-server">2.1. 配置SBA服务端应用程序</a></h3>
<div class="paragraph">
<p>第一步，你需要配置你的服务端程序。
为此，只需要配置一个基础的boot项目（使用 <a href="http://start.spring.io" class="bare">start.spring.io</a> 生成脚手架）。
由于Spring Boot Admin Server同时支持servlet和webflux，所以你需要在其中进行选择，并添加对应的Spring Boot Starter。
在本例中，我们使用servlet作为web starter。</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>将Spring Boot Admin Server的starter添加到你的依赖中:</p>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
    <span class="tag">&lt;groupId&gt;</span>de.codecentric<span class="tag">&lt;/groupId&gt;</span>
    <span class="tag">&lt;artifactId&gt;</span>spring-boot-admin-starter-server<span class="tag">&lt;/artifactId&gt;</span>
    <span class="tag">&lt;version&gt;</span>2.6.6<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span>
<span class="tag">&lt;dependency&gt;</span>
    <span class="tag">&lt;groupId&gt;</span>org.springframework.boot<span class="tag">&lt;/groupId&gt;</span>
    <span class="tag">&lt;artifactId&gt;</span>spring-boot-starter-web<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
</li>
</ol>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>如果你使用的是Spring Boot Admin Server的snapshot版本，那么可能还需要添加spring的sonatype snapshot仓库:</p>
</div>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;repositories&gt;</span>
    <span class="tag">&lt;repository&gt;</span>
        <span class="tag">&lt;id&gt;</span>spring-milestone<span class="tag">&lt;/id&gt;</span>
        <span class="tag">&lt;snapshots&gt;</span>
            <span class="tag">&lt;enabled&gt;</span>false<span class="tag">&lt;/enabled&gt;</span>
        <span class="tag">&lt;/snapshots&gt;</span>
        <span class="tag">&lt;url&gt;</span>http://repo.spring.io/milestone<span class="tag">&lt;/url&gt;</span>
    <span class="tag">&lt;/repository&gt;</span>
    <span class="tag">&lt;repository&gt;</span>
        <span class="tag">&lt;id&gt;</span>spring-snapshot<span class="tag">&lt;/id&gt;</span>
        <span class="tag">&lt;snapshots&gt;</span>
            <span class="tag">&lt;enabled&gt;</span>true<span class="tag">&lt;/enabled&gt;</span>
        <span class="tag">&lt;/snapshots&gt;</span>
        <span class="tag">&lt;url&gt;</span>http://repo.spring.io/snapshot<span class="tag">&lt;/url&gt;</span>
    <span class="tag">&lt;/repository&gt;</span>
    <span class="tag">&lt;repository&gt;</span>
        <span class="tag">&lt;id&gt;</span>sonatype-nexus-snapshots<span class="tag">&lt;/id&gt;</span>
        <span class="tag">&lt;name&gt;</span>Sonatype Nexus Snapshots<span class="tag">&lt;/name&gt;</span>
        <span class="tag">&lt;url&gt;</span>https://oss.sonatype.org/content/repositories/snapshots/<span class="tag">&lt;/url&gt;</span>
        <span class="tag">&lt;snapshots&gt;</span>
            <span class="tag">&lt;enabled&gt;</span>true<span class="tag">&lt;/enabled&gt;</span>
        <span class="tag">&lt;/snapshots&gt;</span>
        <span class="tag">&lt;releases&gt;</span>
            <span class="tag">&lt;enabled&gt;</span>false<span class="tag">&lt;/enabled&gt;</span>
        <span class="tag">&lt;/releases&gt;</span>
    <span class="tag">&lt;/repository&gt;</span>
<span class="tag">&lt;/repositories&gt;</span></code></pre>
</div>
</div>
</td>
</tr>
</table>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>在main class上添加`@EnableAdminServer`注解，启用SBA服务器端配置:</p>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Configuration</span>
<span class="annotation">@EnableAutoConfiguration</span>
<span class="annotation">@EnableAdminServer</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">SpringBootAdminApplication</span> {
    <span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span><span class="type">[]</span> args) {
        SpringApplication.run(SpringBootAdminApplication.class, args);
    }
}</code></pre>
</div>
</div>
</li>
</ol>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
如果你想通过部署war包，以servlet容器的方式来设置SBA，那么请查看 <a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-war/">spring-boot-admin-sample-war</a>。
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>同时也看看 <a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-servlet/">spring-boot-admin-sample-servlet</a>，
其中添加了安全保护。</p>
</div>
</div>
<div class="sect2">
<h3 id="register-client-applications"><a class="anchor" href="#register-client-applications"></a><a class="link" href="#register-client-applications">2.2. 注册客户端应用程序</a></h3>
<div class="paragraph">
<p>要想在SBA服务端注册你的应用，你需要引入SBA客户端，或者是使用
<a href="https://spring.io/projects/spring-cloud">Spring Cloud服务发现</a> (例如 Eureka、Consul等等)。
这里有一个
<a href="#spring-cloud-discovery-static-config">在SBA服务端使用静态配置的简单选项</a>。</p>
</div>
<div class="sect3">
<h4 id="register-clients-via-spring-boot-admin"><a class="anchor" href="#register-clients-via-spring-boot-admin"></a><a class="link" href="#register-clients-via-spring-boot-admin">2.2.1. SBA客户端服务</a></h4>
<div class="paragraph">
<p>所有要注册的应用都需要添加Spring Boot Admin客户端依赖。
如果要想对默认接口进行安全保护，还需要添加 <code>spring-boot-starter-security</code> 依赖。</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>添加spring-boot-admin-starter-client依赖:</p>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
    <span class="tag">&lt;groupId&gt;</span>de.codecentric<span class="tag">&lt;/groupId&gt;</span>
    <span class="tag">&lt;artifactId&gt;</span>spring-boot-admin-starter-client<span class="tag">&lt;/artifactId&gt;</span>
    <span class="tag">&lt;version&gt;</span>2.6.6<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span>
<span class="tag">&lt;dependency&gt;</span>
    <span class="tag">&lt;groupId&gt;</span>org.springframework.boot<span class="tag">&lt;/groupId&gt;</span>
    <span class="tag">&lt;artifactId&gt;</span>spring-boot-starter-security<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
</li>
<li>
<p>配置Spring Boot Admin服务端的URL来开启SBA客户端:</p>
<div class="listingblock">
<div class="title">application.properties</div>
<div class="content">
<pre class="CodeRay highlight"><code>spring.boot.admin.client.url=http://localhost:8080  <i class="conum" data-value="1"></i><b>(1)</b>
management.endpoints.web.exposure.include=*  <i class="conum" data-value="2"></i><b>(2)</b>
management.info.env.enabled=true <i class="conum" data-value="3"></i><b>(3)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>将要注册到的Spring Boot Admin 服务端URL地址。</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>与Spring Boot 2一样，大部分默认接口都没有通过http暴露出来，这里我们将它们全部暴露。在生产环境，您应该酌情选择您要公开的接口。</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>在Spring Boot 2.6版本之后，env信息默认是关闭的。所以我们必须启用它们。</td>
</tr>
</table>
</div>
</li>
<li>
<p>让所有的actuator接口都可以访问:</p>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Configuration</span>
<span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">SecurityPermitAllConfig</span> <span class="directive">extends</span> WebSecurityConfigurerAdapter {
    <span class="annotation">@Override</span>
    <span class="directive">protected</span> <span class="type">void</span> configure(HttpSecurity http) <span class="directive">throws</span> <span class="exception">Exception</span> {
        http.authorizeRequests().anyRequest().permitAll()  <i class="conum" data-value="1"></i><b>(1)</b>
            .and().csrf().disable();
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>为了演示的简单，我们禁用了安全功能。请查看 <a href="#securing-spring-boot-admin">安全处理章节</a> 来学习如何保护您的接口。</td>
</tr>
</table>
</div>
</li>
</ol>
</div>
</div>
<div class="sect3">
<h4 id="discover-clients-via-spring-cloud-discovery"><a class="anchor" href="#discover-clients-via-spring-cloud-discovery"></a><a class="link" href="#discover-clients-via-spring-cloud-discovery">2.2.2. Spring Cloud 服务发现</a></h4>
<div class="paragraph">
<p>如果已经在应用中使用了Spring Cloud Discovery，那么就不需要SBA客户端了。
只需要为Spring Boot Admin服务端添加一个DiscoveryClient，其余的工作都会由我们自动配置完成。</p>
</div>
<div class="paragraph">
<p>下面的步骤中我们使用的是Eureka，但是其它的Spring Cloud Discovery实现也都支持的很好。 这里就有一些使用 <a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-consul/">Consul</a> 和 <a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-zookeeper/">Zookeeper</a> 的例子。</p>
</div>
<div class="paragraph">
<p>另外，也参考一下 <a href="http://projects.spring.io/spring-cloud/spring-cloud.html">Spring Cloud 文档</a>。</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>在依赖中添加spring-cloud-starter-eureka:</p>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
    <span class="tag">&lt;groupId&gt;</span>org.springframework.cloud<span class="tag">&lt;/groupId&gt;</span>
    <span class="tag">&lt;artifactId&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
</li>
<li>
<p>在配置类中添加 <code>@EnableDiscoveryClient</code> 注解以启用服务发现:</p>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Configuration</span>
<span class="annotation">@EnableAutoConfiguration</span>
<span class="annotation">@EnableDiscoveryClient</span>
<span class="annotation">@EnableScheduling</span>
<span class="annotation">@EnableAdminServer</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">SpringBootAdminApplication</span> {
    <span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span><span class="type">[]</span> args) {
        SpringApplication.run(SpringBootAdminApplication.class, args);
    }

    <span class="annotation">@Configuration</span>
    <span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">SecurityPermitAllConfig</span> <span class="directive">extends</span> WebSecurityConfigurerAdapter {
        <span class="annotation">@Override</span>
        <span class="directive">protected</span> <span class="type">void</span> configure(HttpSecurity http) <span class="directive">throws</span> <span class="exception">Exception</span> {
            http.authorizeRequests().anyRequest().permitAll()  <i class="conum" data-value="1"></i><b>(1)</b>
                .and().csrf().disable();
        }
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>为了演示的简单，我们禁用了安全功能。请查看 <a href="#securing-spring-boot-admin">安全处理章节</a> 来学习如何保护您的接口。</td>
</tr>
</table>
</div>
</li>
<li>
<p>告诉Eureka客户端在哪里查找服务:</p>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yml"><span class="key">eureka</span>:   <i class="conum" data-value="1"></i><b>(1)</b>
  <span class="key">instance</span>:
    <span class="key">leaseRenewalIntervalInSeconds</span>: <span class="string"><span class="content">10</span></span>
    <span class="key">health-check-url-path</span>: <span class="string"><span class="content">/actuator/health</span></span>
    <span class="key">metadata-map</span>:
      <span class="key">startup</span>: <span class="string"><span class="content">${random.int}</span></span>    <span class="comment">#needed to trigger info and endpoint update after restart</span>
  <span class="key">client</span>:
    <span class="key">registryFetchIntervalSeconds</span>: <span class="string"><span class="content">5</span></span>
    <span class="key">serviceUrl</span>:
      <span class="key">defaultZone</span>: <span class="string"><span class="content">${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/</span></span>

<span class="key">management</span>:
  <span class="key">endpoints</span>:
    <span class="key">web</span>:
      <span class="key">exposure</span>:
        <span class="key">include</span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">*</span><span class="delimiter">&quot;</span></span>  <i class="conum" data-value="2"></i><b>(2)</b>
  <span class="key">endpoint</span>:
    <span class="key">health</span>:
      <span class="key">show-details</span>: <span class="string"><span class="content">ALWAYS</span></span></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>针对Eureka客户端的配置部分</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>与Spring Boot 2一样，大部分默认接口都没有通过http暴露出来，这里我们将它们全部暴露。在生产环境，您应该酌情选择您要公开的接口。</td>
</tr>
</table>
</div>
</li>
</ol>
</div>
<div class="paragraph">
<p>另外，也参考一下 <a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-eureka/">spring-boot-admin-sample-eureka</a>。</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
你也可以将Spring Boot Admin服务端安装在Eureka服务端上。首先将前文的安装步骤重复一遍，然后将 <code>spring.boot.admin.context-path</code> 设置为除了 <code>"/"</code> 之外的其它路径，这样Spring Boot Admin服务端的用户交互页面就不会和Eureka的冲突了。
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="register-python-applications"><a class="anchor" href="#register-python-applications"></a><a class="link" href="#register-python-applications">2.2.3. 使用Pyctuator注册Python应用程序</a></h4>
<div class="paragraph">
<p>使用 <a href="https://github.com/SolarEdgeTech/pyctuator">Pyctuator</a>，您可以轻松的将Spring Boot Admin与 <a href="https://flask.palletsprojects.com">Flask</a> 或者是 <a href="https://fastapi.tiangolo.com/">FastAPI</a> 轻松的集成在一起。</p>
</div>
<div class="paragraph">
<p>下面的例子使用的是Flask，但是其它web框架也支持的很好。
有关框架的更新列表以及所支持的功能，请查看Pyctuator官方文档。</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>安装pyctuator包:</p>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="bash">pip install pyctuator</code></pre>
</div>
</div>
</li>
<li>
<p>将pyctuator指向你的Flask应用，让它知道Spring Boot Admin是在哪里运行的，从而启用pyctuator:</p>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="python"><span class="keyword">import</span> <span class="include">os</span>
<span class="keyword">from</span> <span class="include">flask</span> <span class="keyword">import</span> <span class="include">Flask</span>
<span class="keyword">from</span> <span class="include">pyctuator.pyctuator</span> <span class="keyword">import</span> <span class="include">Pyctuator</span>

app_name = <span class="string"><span class="delimiter">&quot;</span><span class="content">Flask App with Pyctuator</span><span class="delimiter">&quot;</span></span>
app = Flask(app_name)


<span class="decorator">@app.route</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">/</span><span class="delimiter">&quot;</span></span>)
<span class="keyword">def</span> <span class="function">hello</span>():
    <span class="keyword">return</span> <span class="string"><span class="delimiter">&quot;</span><span class="content">Hello World!</span><span class="delimiter">&quot;</span></span>


Pyctuator(
    app,
    app_name,
    app_url=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://example-app.com</span><span class="delimiter">&quot;</span></span>,
    pyctuator_endpoint_url=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://example-app.com/pyctuator</span><span class="delimiter">&quot;</span></span>,
    registration_url=os.getenv(<span class="string"><span class="delimiter">&quot;</span><span class="content">SPRING_BOOT_ADMIN_URL</span><span class="delimiter">&quot;</span></span>)
)

app.run()</code></pre>
</div>
</div>
</li>
</ol>
</div>
<div class="paragraph">
<p>有关更多的详细信息和示例，请查看Pyctuator的 <a href="https://github.com/SolarEdgeTech/pyctuator/blob/master/README.md">官方文档</a> 以及 <a href="https://github.com/SolarEdgeTech/pyctuator/tree/master/examples">官方示例</a>。</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="client-applications"><a class="anchor" href="#client-applications"></a><a class="link" href="#client-applications">3. 客户端应用程序</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="show-version-in-application-list"><a class="anchor" href="#show-version-in-application-list"></a><a class="link" href="#show-version-in-application-list">3.1. 在应用列表中显示版本号</a></h3>
<div class="paragraph">
<p>对于 <strong>Spring Boot</strong> 应用程序，显示版本号最简单的办法，就是使用 <code>spring-boot-maven-plugin</code> maven插件，然后配置 goal <code>build-info</code>，之后该插件就会生成 <code>META-INF/build-info.properties</code> 文件了。更多详情请查看 <a href="http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-build-info">Spring Boot 参考指南</a>。</p>
</div>
<div class="paragraph">
<p>对于 <strong>非Spring Boot</strong> 应用的话，可以在注册的时候添加 <code>version</code> 或 <code>build.version</code> 参数，这样在应用列表中就会显示版本号了。</p>
</div>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;build&gt;</span>
    <span class="tag">&lt;plugins&gt;</span>
        <span class="tag">&lt;plugin&gt;</span>
            <span class="tag">&lt;groupId&gt;</span>org.springframework.boot<span class="tag">&lt;/groupId&gt;</span>
            <span class="tag">&lt;artifactId&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
            <span class="tag">&lt;executions&gt;</span>
                <span class="tag">&lt;execution&gt;</span>
                    <span class="tag">&lt;goals&gt;</span>
                        <span class="tag">&lt;goal&gt;</span>build-info<span class="tag">&lt;/goal&gt;</span>
                    <span class="tag">&lt;/goals&gt;</span>
                <span class="tag">&lt;/execution&gt;</span>
            <span class="tag">&lt;/executions&gt;</span>
        <span class="tag">&lt;/plugin&gt;</span>
    <span class="tag">&lt;/plugins&gt;</span>
<span class="tag">&lt;/build&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>要想在gradle项目中生成构建信息的话，请在 <code>build.gradle</code> 文件中添加下面的代码:</p>
</div>
<div class="listingblock">
<div class="title">build.gradle</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="groovy">springBoot {
  buildInfo()
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="jmx-bean-management"><a class="anchor" href="#jmx-bean-management"></a><a class="link" href="#jmx-bean-management">3.2. JMX-Bean的管理</a></h3>
<div class="paragraph">
<p>要想在admin页面中与JMX-beans进行交互，必须在应用中引入 <a href="https://jolokia.org/">Jolokia</a>。
由于Jolokia是基于servlet开发的，所以不支持响应式应用。
如果你使用的是 <code>spring-boot-admin-starter-client</code> 这个依赖，那么它自动会为您引入，如果没有的话，则需要手动的将Jolokia添加到依赖中。
针对Spring Boot 2.2.0版本，如果您想通过JMX暴露Spring bean的话，可能需要设置 <code>spring.jmx.enabled=true</code>。</p>
</div>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
    <span class="tag">&lt;groupId&gt;</span>org.jolokia<span class="tag">&lt;/groupId&gt;</span>
    <span class="tag">&lt;artifactId&gt;</span>jolokia-core<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="logfile"><a class="anchor" href="#logfile"></a><a class="link" href="#logfile">3.3. 查看日志文件</a></h3>
<div class="paragraph">
<p>默认情况下，无法通过actuator接口访问日志文件，因此默认Spring Boot Admin中是看不到日志文件的。
要想启用actuator的日志文件接口，需要设置 <code>logging.file.path</code> 或 <code>logging.file.name</code> 来配置Spring Boot读写日志文件。</p>
</div>
<div class="paragraph">
<p>Spring Boot Admin会检测所有看起来像URL的东西，并将其呈现为超链接。</p>
</div>
<div class="paragraph">
<p>ANSI颜色转义语法也是支持的。
你可以自定义一个文件日志的表达式，因为Spring Boot默认情况下是不使用颜色的。</p>
</div>
<div class="listingblock">
<div class="title">application.properties</div>
<div class="content">
<pre>logging.file.name=/var/log/sample-boot-application.log <i class="conum" data-value="1"></i><b>(1)</b>
logging.pattern.file=%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID}){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx <i class="conum" data-value="2"></i><b>(2)</b></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>定义日志文件的写入目录。启用日志文件的actuator接口。</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>文件日志使用自定义的ANSI颜色。</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="show-instance-tags"><a class="anchor" href="#show-instance-tags"></a><a class="link" href="#show-instance-tags">3.4. 显示实例的标签</a></h3>
<div class="paragraph">
<p>您可以为每个实例添加一个 <code>标签（Tags）</code> 来提高其可读性，它们会显示在应用列表以及实例试图中。
默认情况下实例不会被添加任何标签，它取决与客户端有没有向metadata元数据中添加标签或是向其它info接口中指定标签。</p>
</div>
<div class="listingblock">
<div class="title">application.properties</div>
<div class="content">
<pre>#使用metadata元数据
spring.boot.admin.client.instance.metadata.tags.environment=test

#使用info接口
info.tags.environment=test</pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="spring-boot-admin-client"><a class="anchor" href="#spring-boot-admin-client"></a><a class="link" href="#spring-boot-admin-client">3.5. SBA客户端</a></h3>
<div class="paragraph">
<p>Spring Boot Admin客户端会注册在admin的服务端上。
这是通过定期向SBA服务端发送HTTP post请求来完成的，同时也会向服务端提供应用信息。</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
有一些可选的属性可以影响SBA客户端的注册方式。如果这些不满足您的需求，你也可以通过提供 <code>ApplicationFactory</code> 实现的方式手动拓展。
</td>
</tr>
</table>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 1. Spring Boot Admin 客户端配置可选项</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">属性名</th>
<th class="tableblock halign-left valign-top">说明</th>
<th class="tableblock halign-left valign-top">默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">开启Spring Boot Admin 客户端。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">向哪些Spring Boot Admin服务端注册，可以传一个列表，URL中间以逗号分割。这个参数会自动触发。<strong>强制性</strong> 的。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.api-path</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">提供admin服务端的http注册路径。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"instances"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.username<br>
spring.boot.admin.client.password</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">如果SBA服务端启用了HTTP Basic认证，则需要提供用户名和密码。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.period</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">重复注册的间隔（单位毫秒ms）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>10,000</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.connect-timeout</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">注册链接的超时时间（单位毫秒ms）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>5,000</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.read-timeout</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">注册时的读取超时时间（单位毫秒ms）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>5,000</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.auto-registration</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">如果设置成true的话，在应用程序启动完成后，会自动执行注册定时任务。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.auto-deregistration</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">在上下文关闭后是否自动从Spring Boot Admin服务端注销。如果没有设置这个值的话，则会通过CloudPlatform的活动状态来判断。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>null</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.register-once</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">如果设置为true的话，客户端只会注册到一个admin服务端中（根据 <code>spring.boot.admin.instance.url</code> 中定义的顺序）；
如果admin服务端挂掉了的话，则会自动注册到下一个admin服务端。
如果设置为false，那么会注册到所有配置的admin服务端中。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.instance.health-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">注册使用的健康检查url，如果URL不同也可以被覆盖（例如在使用Docker的时候）。在注册时必须时唯一的。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">根据 management-url 和 <code>endpoints.health.id</code> 进行拼接。</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.instance.management-base-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">根据 management-url 在注册时进行计算。这个路径在运行期间才会拼接到base url上。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">通过 <code>management.port</code> 、 service-url 和 <code>server.servlet-path</code> 计算获得。</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.instance.management-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">要注册的Management-url。如果URL不同也可以被覆盖（例如在使用Docker的时候）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">通过 management-base-url 和 <code>management.context-path</code> 计算获得。</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.instance.service-base-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Base url用于计算将要注册的service-url。这个路径在运行期间才会计算，并拼接到base url上。
在Cloudfoundry环境下，你可以通过 <code>spring.boot.admin.client.instance.service-base-url=https://${vcap.application.uris[0]}</code> 来进行切换。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">通过 hostname 和 <code>server.port</code> 计算获得。</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.instance.service-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">将要注册的 Service-url。如果URL不同也可以被覆盖（例如在使用Docker的时候）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">通过 service-base-url 和 <code>server.context-path</code> 计算获得。</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.instance.service-path</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">将要注册的 Service-path。如果URL不同也可以被覆盖（例如以代码的方式设置了context-path）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">/</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.instance.name</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">将要注册的实例名。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">如果设置了 <code>${spring.application.name}</code> 的话就使用这个，否则会使用 <code>"spring-boot-application"</code> 。</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.instance.service-host-type</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">选择向服务端发送哪种host信息:<br>
    * <code>IP</code>: 使用 <code>InetAddress.getHostAddress()</code> 返回的IP<br>
    * <code>HOST_NAME</code>: 使用 <code>InetAddress.getHostName()</code> 返回的单个主机名<br>
    * <code>CANONICAL_HOST_NAME</code>: 使用 <code>InetAddress.geCanonicalHostName()</code> 返回的FQDN(Fully Qualified Domain Name：全限定域名：同时带有主机名和域名的名称。例如：主机名是bigserver,域名是mycompany.com,那么FQDN就是bigserver.mycompany.com)<br>
    如果在服务中设置了 <code>server.address</code> 或者是 <code>management.address</code> 属性，那么这个值会被覆盖掉。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>CANONICAL_HOST_NAME</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.instance.metadata.*</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">与该实例相关联的元数据键值对。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.client.instance.metadata.tags.*</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">与该实例相关联的标签键值对。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 2. 实例元数据可选项</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Key</th>
<th class="tableblock halign-left valign-top">Value</th>
<th class="tableblock halign-left valign-top">默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">user.name<br>
user.password</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">用于访问接口的权限凭证。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="spring-boot-admin-server"><a class="anchor" href="#spring-boot-admin-server"></a><a class="link" href="#spring-boot-admin-server">4. SBA服务端</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_通过代理访问运行的服务端"><a class="anchor" href="#_通过代理访问运行的服务端"></a><a class="link" href="#_通过代理访问运行的服务端">4.1. 通过代理访问运行的服务端</a></h3>
<div class="paragraph">
<p>如果Spring Boot Admin服务端是通过反向代理访问的，那么可能需要通过 (<code>spring.boot.admin.ui.public-url</code>) 配置一个公开的url来访问服务端。
此外，当反向代理阻断了https链接时，可能需要配置 <code>server.forward-headers-strategy=native</code> （同时请参考 <a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-use-tomcat-behind-a-proxy-server">Spring Boot 参考指南</a>）。</p>
</div>
</div>
<div class="sect2">
<h3 id="_配置项"><a class="anchor" href="#_配置项"></a><a class="link" href="#_配置项">4.2. 配置项</a></h3>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">属性名</th>
<th class="tableblock halign-left valign-top">说明</th>
<th class="tableblock halign-left valign-top">默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.server.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">开启Spring Boot Admin 服务端。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.context-path</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">访问Admin服务端静态资源以及API的上下文前缀。这是相对于Dispatcher-Servlet来说的。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.monitor.status-interval</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">检查实例状态的时间间隔。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">10,000ms</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.monitor.status-lifetime</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">状态的生命周期。只要最后一次的状态没有过期就不会更新。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">10,000ms</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.monitor.info-interval</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">检查实例信息的时间间隔。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1m</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.monitor.info-lifetime</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">信息的生命周期。只要最后一次的信息没有过期就不会更新。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1m</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.monitor.default-timeout</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">请求默认的超时时间。可以使用 <code>spring.boot.admin.monitor.timeout.*</code> 属性配置某个特定接口的超时时间。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">10,000</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.monitor.timeout.*</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">针对某个接口id超时时间的键值对配置方式。默认情况下就是 default-timeout。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.monitor.default-retries</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">请求失败的默认重试次数。修改请求 (<code>PUT</code>, <code>POST</code>, <code>PATCH</code>, <code>DELETE</code>) 永远不会重试。
可以使用 <code>spring.boot.admin.monitor.retries.*</code> 属性覆盖某个特定接口的重试次数。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.monitor.retries.*</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">针对某个接口id重试次数的键值对配置方式。默认情况下就是 default-retries。修改请求 (<code>PUT</code>, <code>POST</code>, <code>PATCH</code>, <code>DELETE</code>) 永远不会重试。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.metadata-keys-to-sanitize</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">根据正则表达式匹配元数据的key，匹配到的结果在所有的json输出中会被清除。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>".<strong>password$", ".*secret$", ".*key$", ".*token$", ".*credentials.</strong>", ".*vcap_services$"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.probed-endpoints</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">针对Spring Boot 1.x版本的客户端应用，SBA使用该选项来配置特定接口。
如果路径和id不同，可以设置为 id:path（比如 health:ping）..</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"health", "env", "metrics", "httptrace:trace", "threaddump:dump", "jolokia", "info", "logfile", "refresh", "flyway", "liquibase", "heapdump", "loggers", "auditevents"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.instance-auth.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">开启从spring properties配置文件中读取授权信息。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.instance-auth.default-user-name</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">服务注册所使用的默认用户名。前提是 <code>spring.boot.admin.instance-auth.enabled</code> 属性必须设置成 <code>true</code> 。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>null</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.instance-auth.default-password</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">服务注册所使用的默认密码。前提是 <code>spring.boot.admin.instance-auth.enabled</code> 属性必须设置成 <code>true</code> 。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>null</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.instance-auth.service-map.*.user-name</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">某个指定名称的服务注册所使用的用户名。前提是 <code>spring.boot.admin.instance-auth.enabled</code> 属性必须设置成 <code>true</code> 。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.instance-auth.service-map.*.user-password</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">某个指定名称的服务注册所使用的密码。前提是 <code>spring.boot.admin.instance-auth.enabled</code> 属性必须设置成 <code>true</code> 。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.instance-proxy.ignored-headers</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">向客户端转发请求时忽略哪些header。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"Cookie", "Set-Cookie", "Authorization"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.public-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">构建页面的时候所使用的base href。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">如果是通过反向代理进行请求（用到了path重写），那么可以使用该选项来配置正确的引用地址。如果 host/port 被省略了，那么会从请求中推断出来。</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.brand</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">导航栏所使用的品牌标识。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"&lt;img src="assets/img/icon-spring-boot-admin.svg"&gt;&lt;span&gt;Spring Boot Admin&lt;/span&gt;"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.title</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">页面中想要显示的标题。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"Spring Boot Admin"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.login-icon</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">登录页面所显示的图标。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"assets/img/icon-spring-boot-admin.svg"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.favicon</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">配置默认的favicon，用作图标和桌面通知图标。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"assets/img/favicon.png"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.favicon-danger</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">配置默认的favicon，用作图标和桌面通知图标，在服务挂掉的时候显示。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"assets/img/favicon-danger.png"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.remember-me-enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">切换在登录页面是否显示记住我复选框。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.poll-timer.cache</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">获取最新缓存数据的间隔（单位毫秒ms）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>2500</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.poll-timer.datasource</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">获取最新数据源数据的间隔（单位毫秒ms）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>2500</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.poll-timer.gc</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">获取最新gc数据的间隔（单位毫秒ms）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>2500</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.poll-timer.process</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">获取最新cpu数据的间隔（单位毫秒ms）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>2500</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.poll-timer.memory</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">获取最新内存数据的间隔（单位毫秒ms）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>2500</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.ui.poll-timer.threads</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">获取最新线程数据的间隔（单位毫秒ms）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>2500</code></p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="spring-cloud-discovery-support"><a class="anchor" href="#spring-cloud-discovery-support"></a><a class="link" href="#spring-cloud-discovery-support">4.3. Spring Cloud 服务发现</a></h3>
<div class="paragraph">
<p>Spring Boot Admin服务端可以使用Spring Clouds 的 <code>DiscoveryClient</code> 来发现服务。
其优点是客户端不必依赖 <code>spring-boot-admin-starter-client</code> 了。
你只需在admin服务端添加一个 <code>DiscoveryClient</code> 的实现 - 其它一切都会自动配置完成。</p>
</div>
<div class="sect3">
<h4 id="spring-cloud-discovery-static-config"><a class="anchor" href="#spring-cloud-discovery-static-config"></a><a class="link" href="#spring-cloud-discovery-static-config">4.3.1. 使用SimpleDiscoveryClient进行静态配置</a></h4>
<div class="paragraph">
<p>Spring Cloud提供了一个 <code>SimpleDiscoveryClient</code>。它允许我们通过静态配置的方式指定客户端应用:</p>
</div>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
    <span class="tag">&lt;groupId&gt;</span>org.springframework.cloud<span class="tag">&lt;/groupId&gt;</span>
    <span class="tag">&lt;artifactId&gt;</span>spring-cloud-starter<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yml"><span class="key">spring</span>:
  <span class="key">cloud</span>:
    <span class="key">discovery</span>:
      <span class="key">client</span>:
        <span class="key">simple</span>:
          <span class="key">instances</span>:
            <span class="key">test</span>:
              - <span class="string"><span class="content">uri: http://instance1.intern:8080</span></span>
                <span class="key">metadata</span>:
                  <span class="key">management.context-path</span>: <span class="string"><span class="content">/actuator</span></span>
              - <span class="string"><span class="content">uri: http://instance2.intern:8080</span></span>
                <span class="key">metadata</span>:
                  <span class="key">management.context-path</span>: <span class="string"><span class="content">/actuator</span></span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_其它方式的服务发现客户端"><a class="anchor" href="#_其它方式的服务发现客户端"></a><a class="link" href="#_其它方式的服务发现客户端">4.3.2. 其它方式的服务发现客户端</a></h4>
<div class="paragraph">
<p>Spring Boot Admin同时也支持其它Spring Cloud <code>DiscoveryClient</code> 的实现（比如Eureka, Zookeeper, Consul, &#8230;&#8203;）。
只需要将他们添加到Spring Boot Admin服务端并正确配置即可。
这里有一份 <a href="#discover-clients-via-spring-cloud-discovery">使用Eureka作为实现</a> 的示例。</p>
</div>
</div>
<div class="sect3">
<h4 id="_转换服务实例"><a class="anchor" href="#_转换服务实例"></a><a class="link" href="#_转换服务实例">4.3.3. 转换服务实例</a></h4>
<div class="paragraph">
<p>服务的注册信息中是通过 <code>ServiceInstanceConverter</code> 来进行转换的。Spring Boot Admin提供了一个默认转换方式，还有一个Eureka转换方式的实现。
这些都是自动配置并选择的。</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
你也可以通过SBA服务端配置选项，来修改应用注册时使用哪些信息以及哪些实例元数据。元数据的值会优先于服务端的配置。
如果这么多选项仍然满足不了您的需求，那么您也可以自定义一个`ServiceInstanceConverter`。
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
在使用Eureka的时候，<code>healthCheckUrl`选项会被Eureka用在健康检查上，
它也可以通过 `eureka.instance.healthCheckUrl</code> 属性配置在您的客户端上。
</td>
</tr>
</table>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 3. 实例支持的元数据选项</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Key</th>
<th class="tableblock halign-left valign-top">Value</th>
<th class="tableblock halign-left valign-top">默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">user.name<br>
user.password</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">访问接口所使用的凭证。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">management.scheme</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">服务URL中使用的scheme，用于访问actuator接口。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">management.address</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">服务URL中使用的address，用于访问actuator接口。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">management.port</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">服务URL中使用的port，用于访问actuator接口。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">management.context-path</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">服务URL后添加的上下文路径，用于访问actuator接口。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>${spring.boot.admin.discovery.converter.management-context-path}</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">health.path</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">服务URL后添加的路径，用于健康检查。如果配置了 <code>EurekaServiceInstanceConverter</code> 则会被忽略。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>${spring.boot.admin.discovery.converter.health-endpoint}</code></p></td>
</tr>
</tbody>
</table>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 4. 服务发现配置可选项</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">属性名</th>
<th class="tableblock halign-left valign-top">说明</th>
<th class="tableblock halign-left valign-top">默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.discovery.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">开启admin服务端的DiscoveryClient支持。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.discovery.converter.management-context-path</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">当management-url被 <code>DefaultServiceInstanceConverter</code> 转换时，这个路径会拼接到发现服务的service-url后面。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>/actuator</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.discovery.converter.health-endpoint-path</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">当health-url被 <code>DefaultServiceInstanceConverter</code> 转换时，这个路径会拼接到发现服务的management-url后面。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"health"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.discovery.ignored-services</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">在发现服务的时候，这些服务会被忽略，不会作为服务注册到服务端。支持一些简单的表达式（比如 "foo*", "*bar", "foo*bar*"）。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.discovery.services</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">在发现服务的时候，这些服务会被包含进来，作为服务注册到服务端。支持一些简单的表达式（比如 "foo*", "*bar", "foo*bar*"）。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"*"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.discovery.ignored-instances-metadata</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">如果服务实例的元数据被列表匹配到至少一项，那么这个服务就会被忽略。 (例如 "discoverable=false")</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.discovery.instances-metadata</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">如果服务实例的元数据被列表匹配到至少一项，那么这个服务就会被引入进来。 (例如 "discoverable=false")</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="_cloudfoundry"><a class="anchor" href="#_cloudfoundry"></a><a class="link" href="#_cloudfoundry">4.3.4. CloudFoundry</a></h4>
<div class="paragraph">
<p>如果您想将应用部署到CloudFoundry上，那么就 <strong><em>必须</em></strong> 配置 <code>vcap.application.application_id</code> 以及 <code>vcap.application.instance_index</code> 这两个选项，它们会被添加到元数据中，这样才能正确注册到Spring Boot Admin服务端。
下面是一个针对Eureka的简单配置:</p>
</div>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yml"><span class="key">eureka</span>:
  <span class="key">instance</span>:
    <span class="key">hostname</span>: <span class="string"><span class="content">${vcap.application.uris[0]}</span></span>
    <span class="key">nonSecurePort</span>: <span class="string"><span class="content">80</span></span>
    <span class="key">metadata-map</span>:
      <span class="key">applicationId</span>: <span class="string"><span class="content">${vcap.application.application_id}</span></span>
      <span class="key">instanceId</span>: <span class="string"><span class="content">${vcap.application.instance_index}</span></span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="clustering-support"><a class="anchor" href="#clustering-support"></a><a class="link" href="#clustering-support">4.4. 集群</a></h3>
<div class="paragraph">
<p>Spring Boot Admin服务端支持通过Hazelcast的方式建立集群。当提供 <code>HazelcastConfig</code> 或 <code>HazelcastInstance</code> Bean的时候会自动开启。 你也可以持久化Hazelcast的配置，这样在服务重启之后仍然能保持之前的状态。 同时推荐参考 <a href="http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-hazelcast/">Spring Boot对Hazelcast的支持</a>。</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>将Hazelcast添加到依赖中:</p>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
    <span class="tag">&lt;groupId&gt;</span>com.hazelcast<span class="tag">&lt;/groupId&gt;</span>
    <span class="tag">&lt;artifactId&gt;</span>hazelcast<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
</li>
<li>
<p>初始化HazelcastConfig:</p>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Bean</span>
<span class="directive">public</span> Config hazelcastConfig() {
  <span class="comment">// This map is used to store the events.</span>
  <span class="comment">// It should be configured to reliably hold all the data,</span>
  <span class="comment">// Spring Boot Admin will compact the events, if there are too many</span>
  MapConfig eventStoreMap = <span class="keyword">new</span> MapConfig(DEFAULT_NAME_EVENT_STORE_MAP).setInMemoryFormat(InMemoryFormat.OBJECT)
      .setBackupCount(<span class="integer">1</span>)
      .setMergePolicyConfig(<span class="keyword">new</span> MergePolicyConfig(PutIfAbsentMergePolicy.class.getName(), <span class="integer">100</span>));

  <span class="comment">// This map is used to deduplicate the notifications.</span>
  <span class="comment">// If data in this map gets lost it should not be a big issue as it will atmost</span>
  <span class="comment">// lead to</span>
  <span class="comment">// the same notification to be sent by multiple instances</span>
  MapConfig sentNotificationsMap = <span class="keyword">new</span> MapConfig(DEFAULT_NAME_SENT_NOTIFICATIONS_MAP)
      .setInMemoryFormat(InMemoryFormat.OBJECT).setBackupCount(<span class="integer">1</span>)
      .setEvictionConfig(<span class="keyword">new</span> EvictionConfig().setEvictionPolicy(EvictionPolicy.LRU)
          .setMaxSizePolicy(MaxSizePolicy.PER_NODE))
      .setMergePolicyConfig(<span class="keyword">new</span> MergePolicyConfig(PutIfAbsentMergePolicy.class.getName(), <span class="integer">100</span>));

  Config config = <span class="keyword">new</span> Config();
  config.addMapConfig(eventStoreMap);
  config.addMapConfig(sentNotificationsMap);
  config.setProperty(<span class="string"><span class="delimiter">&quot;</span><span class="content">hazelcast.jmx</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">true</span><span class="delimiter">&quot;</span></span>);

  <span class="comment">// WARNING: This setups a local cluster, you change it to fit your needs.</span>
  config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(<span class="predefined-constant">false</span>);
  TcpIpConfig tcpIpConfig = config.getNetworkConfig().getJoin().getTcpIpConfig();
  tcpIpConfig.setEnabled(<span class="predefined-constant">true</span>);
  tcpIpConfig.setMembers(singletonList(<span class="string"><span class="delimiter">&quot;</span><span class="content">127.0.0.1</span><span class="delimiter">&quot;</span></span>));
  <span class="keyword">return</span> config;
}</code></pre>
</div>
</div>
</li>
</ol>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 5. Hazelcast配置可选项</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">属性名</th>
<th class="tableblock halign-left valign-top">说明</th>
<th class="tableblock halign-left valign-top">默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.hazelcast.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">开启对Hazelcast的支持</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.hazelcast.event-store</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">对Hazelcast-map事件的存储名称</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"spring-boot-admin-event-store"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.hazelcast.sent-notifications</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">用于清除Hazelcast-map对应名称的重复通知</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"spring-boot-admin-sent-notifications"</code></p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_消息通知"><a class="anchor" href="#_消息通知"></a><a class="link" href="#_消息通知">4.5. 消息通知</a></h3>
<div class="sect3">
<h4 id="mail-notifications"><a class="anchor" href="#mail-notifications"></a><a class="link" href="#mail-notifications">4.5.1. 邮件通知</a></h4>
<div class="paragraph">
<p>邮件通知是以HTML格式渲染的电子邮件，它使用 <a href="https://www.thymeleaf.org/">Thymeleaf</a> 作为模板。 要想开启邮件通知，需要使用 <code>spring-boot-starter-mail</code> 配置 <code>JavaMailSender</code> 并设置一个收件人。</p>
</div>
<div class="imageblock">
<div class="content">
<img src="images/mail-notification-sample.png" alt="Sample Mail Notification">
</div>
<div class="title">图片 1. 邮件通知的例子</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
为了防止敏感信息被泄露，默认邮件模板中不显示任何实例的元数据。如果你想显示的话，可以自定义模板。
</td>
</tr>
</table>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>将spring-boot-starter-mail添加到依赖中:</p>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
    <span class="tag">&lt;groupId&gt;</span>org.springframework.boot<span class="tag">&lt;/groupId&gt;</span>
    <span class="tag">&lt;artifactId&gt;</span>spring-boot-starter-mail<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
</li>
<li>
<p>配置一个JavaMailSender</p>
<div class="listingblock">
<div class="title">application.properties</div>
<div class="content">
<pre>spring.mail.host=smtp.example.com
spring.boot.admin.notify.mail.to=admin@example.com</pre>
</div>
</div>
</li>
<li>
<p>根据下面的可选项配置邮件</p>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 6. 邮件提醒配置的可选项</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">属性名</th>
<th class="tableblock halign-left valign-top">说明</th>
<th class="tableblock halign-left valign-top">面若防治</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.mail.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">开启邮件提醒</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.mail.ignore-changes</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">要忽略的状态变化，使用逗号分割。格式是: "&lt;from-status&gt;:&lt;to-status&gt;"。允许使用通配符</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"UNKNOWN:UP"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.mail.template</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">用于渲染的Thymeleaf模板路径</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"classpath:/META-INF/spring-boot-admin-server/mail/status-changed.html"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.mail.to</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">邮件收件人列表，用逗号进行分割</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"root@localhost"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.mail.cc</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">副本收件人列表，用逗号分割</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.mail.from</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">邮件发送人</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"Spring Boot Admin &lt;noreply@localhost&gt;"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.mail.additional-properties</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">可以从模板读取的其它属性</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</li>
</ol>
</div>
</div>
<div class="sect3">
<h4 id="pagerduty-notifications"><a class="anchor" href="#pagerduty-notifications"></a><a class="link" href="#pagerduty-notifications">4.5.2. PagerDuty通知</a></h4>
<div class="paragraph">
<p>To enable <a href="https://www.pagerduty.com/">PagerDuty</a> notifications you just have to add a generic service to your PagerDuty-account and set <code>spring.boot.admin.notify.pagerduty.service-key</code> to the service-key you received.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 7. PagerDuty notifications configuration options</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Property name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Default value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.pagerduty.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Enable mail notifications</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.pagerduty.ignore-changes</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Comma-delimited list of status changes to be ignored. Format: "&lt;from-status&gt;:&lt;to-status&gt;". Wildcards allowed.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"UNKNOWN:UP"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.pagerduty.service-key</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Service-key to use for PagerDuty</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.pagerduty.url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The Pagerduty-rest-api url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"https://events.pagerduty.com/generic/2010-04-15/create_event.json"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.pagerduty.description</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Description to use in the event. SpEL-expressions are supported</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"#{instance.registration.name}/#{instance.id} is #{instance.statusInfo.status}"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.pagerduty.client</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Client-name to use in the event</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.pagerduty.client-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Client-url to use in the event</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="opsgenie-notifications"><a class="anchor" href="#opsgenie-notifications"></a><a class="link" href="#opsgenie-notifications">4.5.3. OpsGenie通知</a></h4>
<div class="paragraph">
<p>To enable <a href="https://www.opsgenie.com/">OpsGenie</a> notifications you just have to add a new JSON Rest API integration to your OpsGenie account and set <code>spring.boot.admin.notify.opsgenie.api-key</code> to the apiKey you received.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 8. OpsGenie notifications configuration options</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Property name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Default value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.opsgenie.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Enable OpsGenie notifications</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.opsgenie.ignore-changes</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Comma-delimited list of status changes to be ignored. Format: "&lt;from-status&gt;:&lt;to-status&gt;". Wildcards allowed.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"UNKNOWN:UP"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.opsgenie.api-key</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">apiKey you received when creating the integration</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.opsgenie.url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">OpsGenie Alert API url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"https://api.opsgenie.com/v2/alerts"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.opsgenie.description</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Description to use in the event. SpEL-expressions are supported</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"#{instance.registration.name}/#{instance.id} is #{instance.statusInfo.status}"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.opsgenie.actions</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Comma separated list of actions that can be executed.</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.opsgenie.source</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Field to specify source of alert. By default, it will be assigned to IP address of incoming request.</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.opsgenie.tags</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Comma separated list of labels attached to the alert.</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.opsgenie.entity</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The entity the alert is related to.</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.opsgenie.user</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Default owner of the execution. If user is not specified, the system becomes owner of the execution.</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="hipchat-notifications"><a class="anchor" href="#hipchat-notifications"></a><a class="link" href="#hipchat-notifications">4.5.4. Hipchat通知</a></h4>
<div class="paragraph">
<p>To enable <a href="https://www.hipchat.com/">Hipchat</a> notifications you need to create an API token on your Hipchat account and set the appropriate configuration properties.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 9. Hipchat notifications configuration options</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Property name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Default value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.hipchat.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Enable Hipchat notifications</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.hipchat.ignore-changes</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Comma-delimited list of status changes to be ignored. Format: "&lt;from-status&gt;:&lt;to-status&gt;". Wildcards allowed.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"UNKNOWN:UP"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.hipchat.url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The HipChat REST API (V2) URL</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.hipchat.auth-token</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The API token with access to the notification room</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.hipchat.room-id</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The ID or url-encoded name of the room to send notifications to</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.hipchat.notify</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Whether the message should trigger a user notification</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>false</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.hipchat.description</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Description to use in the event. SpEL-expressions are supported</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"&lt;strong&gt;#{instance.registration.name}&lt;/strong&gt;/#{instance.id} is &lt;strong&gt;#{event.statusInfo.status}&lt;/strong&gt;"</code></p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="slack-notifications"><a class="anchor" href="#slack-notifications"></a><a class="link" href="#slack-notifications">4.5.5. Slack通知</a></h4>
<div class="paragraph">
<p>To enable <a href="https://slack.com/">Slack</a> notifications you need to add a incoming Webhook under custom integrations on your Slack account and configure it appropriately.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 10. Slack notifications configuration options</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Property name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Default value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.slack.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Enable Slack notifications</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.slack.ignore-changes</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Comma-delimited list of status changes to be ignored. Format: "&lt;from-status&gt;:&lt;to-status&gt;". Wildcards allowed.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"UNKNOWN:UP"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.slack.webhook-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The Slack Webhook URL to send notifications to.</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.slack.channel</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional channel name (without # at the beginning). If different than channel in Slack Webhooks settings</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.slack.icon</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional icon name (without surrounding colons). If different than icon in Slack Webhooks settings</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.slack.username</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional username to send notification if different than in Slack Webhooks settings</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Spring Boot Admin</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.slack.message</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Message to use in the event. SpEL-expressions and Slack markups are supported</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"*#{instance.registration.name}* (#{instance.id}) is *#{event.statusInfo.status}*"</code></p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="letschat-notifications"><a class="anchor" href="#letschat-notifications"></a><a class="link" href="#letschat-notifications">4.5.6. Let&#8217;s Chat通知</a></h4>
<div class="paragraph">
<p>To enable <a href="https://sdelements.github.io/lets-chat/">Let&#8217;s Chat</a> notifications you need to add the host url and add the API token and username from Let&#8217;s Chat</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 11. Let&#8217;s Chat notifications configuration options</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Property name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Default value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.letschat.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Enable let´s Chat notifications</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.letschat.ignore-changes</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Comma-delimited list of status changes to be ignored. Format: "&lt;from-status&gt;:&lt;to-status&gt;". Wildcards allowed.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"UNKNOWN:UP"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.letschat.url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The let´s Chat Host URL to send notifications</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.letschat.room</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">the room where to send the messages</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.letschat.token</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">the token to access the let´s Chat API</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.letschat.username</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The username for which the token was created</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Spring Boot Admin</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.letschat.message</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Message to use in the event. SpEL-expressions are supported</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"*#{instance.registration.name}* (#{instance.id}) is *#{event.statusInfo.status}*"</code></p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="ms-teams-notifications"><a class="anchor" href="#ms-teams-notifications"></a><a class="link" href="#ms-teams-notifications">4.5.7. Microsoft Teams通知</a></h4>
<div class="paragraph">
<p>To enable Microsoft Teams notifications you need to setup a connector webhook url and set the appropriate configuration property.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 12. Microsoft Teams notifications configuration options</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Property name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Default value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.ms-teams.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Enable Microsoft Teams notifications</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.ms-teams.webhook-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The Microsoft Teams webhook url to send the notifications to.</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.ms-teams.deRegisteredTitle</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Title of the Teams message when an app de-registers.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">De-Registered</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.ms-teams.registeredTitle</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Title of the Teams message when an app dregisters.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Registered</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.ms-teams.statusChangedTitle</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Title of the Teams message when an app changes status.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Status Changed</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.ms-teams.messageSummary</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Summary section of every Teams message originating from Spring Boot Admin.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Spring Boot Admin Notification</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.ms-teams.theme_color</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Set the theme color. SpEL-expressions are supported.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>#{event.type == 'STATUS_CHANGED' ? (event.statusInfo.status=='UP' ? '6db33f' : 'b32d36') : '439fe0'}</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.ms-teams.deregister_activity_subtitle</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Subtitle of the Activity section of the Teams message when an app de-registers. SpEL-expressions are supported.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>#{instance.registration.name} with id #{instance.id} has de-registered from Spring Boot Admin</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.ms-teams.register_activity_subtitle</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Subtitle of the Activity section of the Teams message when an app registers. SpEL-expressions are supported.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>#{instance.registration.name} with id #{instance.id} has registered with Spring Boot Admin</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.ms-teams.status_activity_subtitle</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Subtitle of the Activity section of the Teams message when an app changes status. SpEL-expressions are supported.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>#{instance.registration.name} with id #{instance.id} changed status from #{lastStatus} to #{event.statusInfo.status}</code></p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="telegram-notifications"><a class="anchor" href="#telegram-notifications"></a><a class="link" href="#telegram-notifications">4.5.8. Telegram通知</a></h4>
<div class="paragraph">
<p>To enable <a href="https://telegram.org/">Telegram</a> notifications you need to create and authorize a telegram bot and set the appropriate configuration properties for auth-token and chat-id.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 13. Telegram notifications configuration options</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Property name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Default value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.telegram.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Enable Telegram notifications</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.telegram.auth-token</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The token identifying und authorizing your Telegram bot (e.g. <code>123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11</code>).</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.telegram.chat-id</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Unique identifier for the target chat or username of the target channel</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.telegram.disable-notify</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">If true users will receive a notification with no sound.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>false</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.telegram.parse_mode</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The parsing mode for the sent message. Currently <code>`HTML'</code> and <code>'Markdown'</code> are supported.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>'HTML'</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.telegram.message</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Text to send. SpEL-expressions are supported.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"&lt;strong&gt;#{instance.registration.name}&lt;/strong&gt;/#{instance.id} is &lt;strong&gt;#{event.statusInfo.status}&lt;/strong&gt;"</code></p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="discord-notifications"><a class="anchor" href="#discord-notifications"></a><a class="link" href="#discord-notifications">4.5.9. Discord通知</a></h4>
<div class="paragraph">
<p>To enable Discord notifications you need to create a webhook and set the appropriate configuration property.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 14. Discord notifications configuration options</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Property name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Default value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.discord.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Enable Discord notifications</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.discord.webhook-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The Discord webhook url to send the notifications to.</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.discord.username</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional username.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><em>Default set in Discord</em></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.discord.avatar-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional URL to avatar.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><em>Default set in Discord</em></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.discord.tts</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">If the message is a text to speech message.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>false</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.discord.message</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Text to send. SpEL-expressions are supported.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"*#{instance.registration.name}* (#{instance.id}) is *#{event.statusInfo.status}*"</code></p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="notification-proxy"><a class="anchor" href="#notification-proxy"></a><a class="link" href="#notification-proxy">4.5.10. 为消息通知配置代理</a></h4>
<div class="paragraph">
<p>所有的消息通知都是使用 <code>RestTemplate</code> 来进行发送的，所以我们可以为其配置一个代理。</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 15. 通知代理的可选配置</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">属性名</th>
<th class="tableblock halign-left valign-top">说明</th>
<th class="tableblock halign-left valign-top">默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.proxy.host</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">代理的 host</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.proxy.port</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">代理的 port</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.proxy.username</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">代理的 username (如果代理需要身份认证的话)</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.proxy.password</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">代理的 password (如果代理需要身份认证的话)</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="reminder-notifications"><a class="anchor" href="#reminder-notifications"></a><a class="link" href="#reminder-notifications">4.5.11. 通知发送程序</a></h4>
<div class="paragraph">
<p><code>RemindingNotifier</code> 会在应用停机/离线的时候发送消息通知，它会将通知的发送委托给另外一个通知发送程序。</p>
</div>
<div class="paragraph">
<p>默认情况下，这个通知发送程序会在一个已注册发生 <code>停机</code> 或 <code>离线</code> 的时候触发。
你也可以通过 <code>setReminderStatuses()</code> 来修改这个行为。
当这个状态变成了无需触发，或者是相关服务注销了的话，这个通知发送程序就会结束。</p>
</div>
<div class="paragraph">
<p>默认情况下，通知发送程序每隔10分钟发送一次，可以使用 <code>setReminderPeriod()</code> 对这个间隔进行修改。
<code>RemindingNotifier</code> 本身不会开启后台线程来调用通知发送程序，你需要按照下面的示例来处理这个问题;</p>
</div>
<div class="listingblock">
<div class="title">如何配置通知发送程序</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Configuration</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">NotifierConfiguration</span> {
    <span class="annotation">@Autowired</span>
    <span class="directive">private</span> Notifier notifier;

    <span class="annotation">@Primary</span>
    <span class="annotation">@Bean</span>(initMethod = <span class="string"><span class="delimiter">&quot;</span><span class="content">start</span><span class="delimiter">&quot;</span></span>, destroyMethod = <span class="string"><span class="delimiter">&quot;</span><span class="content">stop</span><span class="delimiter">&quot;</span></span>)
    <span class="directive">public</span> RemindingNotifier remindingNotifier() {
        RemindingNotifier notifier = <span class="keyword">new</span> RemindingNotifier(notifier, repository);
        notifier.setReminderPeriod(<span class="predefined-type">Duration</span>.ofMinutes(<span class="integer">10</span>)); <i class="conum" data-value="1"></i><b>(1)</b>
        notifier.setCheckReminderInverval(<span class="predefined-type">Duration</span>.ofSeconds(<span class="integer">10</span>)); <i class="conum" data-value="2"></i><b>(2)</b>
        <span class="keyword">return</span> notifier;
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>通知发送程序会每隔10分钟发送一次。</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>每隔10秒种安排一次通知发送。</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="filtering-notifications"><a class="anchor" href="#filtering-notifications"></a><a class="link" href="#filtering-notifications">4.5.12. 过滤通知</a></h4>
<div class="paragraph">
<p><code>FilteringNotifier</code> 允许在运行时添加/删除消息通知过滤的规则。
它会将通知的发送委托给另一个发送程序。</p>
</div>
<div class="paragraph">
<p>如果向 <code>ApplicationContext</code> 添加了 <code>FilteringNotifier</code>，那么RESTful页面中的 <code>消息通知/过滤器</code> 就可以访问了。</p>
</div>
<div class="paragraph">
<p>尤其时在部署应用的时候，如果你不想接受提醒，此时过滤器就能帮到你。
在停止应用之前你可以通过 <code>POST</code> 请求发送一个（带有过期时间的）过滤条件。</p>
</div>
<div class="listingblock">
<div class="title">如何配置过滤器</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Configuration</span>(proxyBeanMethods = <span class="predefined-constant">false</span>)
<span class="directive">public</span> <span class="type">class</span> <span class="class">NotifierConfig</span> {

  <span class="directive">private</span> <span class="directive">final</span> InstanceRepository repository;

  <span class="directive">private</span> <span class="directive">final</span> ObjectProvider&lt;<span class="predefined-type">List</span>&lt;Notifier&gt;&gt; otherNotifiers;

  <span class="directive">public</span> NotifierConfig(InstanceRepository repository, ObjectProvider&lt;<span class="predefined-type">List</span>&lt;Notifier&gt;&gt; otherNotifiers) {
    <span class="local-variable">this</span>.repository = repository;
    <span class="local-variable">this</span>.otherNotifiers = otherNotifiers;
  }

  <span class="annotation">@Bean</span>
  <span class="directive">public</span> FilteringNotifier filteringNotifier() { <i class="conum" data-value="1"></i><b>(1)</b>
    CompositeNotifier delegate = <span class="keyword">new</span> CompositeNotifier(<span class="local-variable">this</span>.otherNotifiers.getIfAvailable(<span class="predefined-type">Collections</span>::emptyList));
    <span class="keyword">return</span> <span class="keyword">new</span> FilteringNotifier(delegate, <span class="local-variable">this</span>.repository);
  }

  <span class="annotation">@Primary</span>
  <span class="annotation">@Bean</span>(initMethod = <span class="string"><span class="delimiter">&quot;</span><span class="content">start</span><span class="delimiter">&quot;</span></span>, destroyMethod = <span class="string"><span class="delimiter">&quot;</span><span class="content">stop</span><span class="delimiter">&quot;</span></span>)
  <span class="directive">public</span> RemindingNotifier remindingNotifier() { <i class="conum" data-value="2"></i><b>(2)</b>
    RemindingNotifier notifier = <span class="keyword">new</span> RemindingNotifier(filteringNotifier(), <span class="local-variable">this</span>.repository);
    notifier.setReminderPeriod(<span class="predefined-type">Duration</span>.ofMinutes(<span class="integer">10</span>));
    notifier.setCheckReminderInverval(<span class="predefined-type">Duration</span>.ofSeconds(<span class="integer">10</span>));
    <span class="keyword">return</span> notifier;
  }

}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>使用delegate添加一个 <code>FilteringNotifier</code> Bean (例如在配置 <code>MailNotifier</code> 时)</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>使用 <code>FilteringNotifier</code> 作为delegate，将 <code>RemindingNotifier</code> 添加为primary bean。</td>
</tr>
</table>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
这个示例结合了消息提醒和通知过滤。
这可以让你在部署应用后的一段时间内（直到过滤条件过期）不会收到消息通知。
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="DingTalk-notifications"><a class="anchor" href="#DingTalk-notifications"></a><a class="link" href="#DingTalk-notifications">4.5.13. 钉钉通知</a></h4>
<div class="paragraph">
<p>要想启用 <a href="https://www.dingtalk.com/">DingTalk</a> 消息通知，你需要创建并配置钉钉机器人的授权，并为 webhookUrl 和 secret 提供正确的配置。</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">表格 16. 钉钉消息通知配置可选项</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">属性名</th>
<th class="tableblock halign-left valign-top">说明</th>
<th class="tableblock halign-left valign-top">默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.dingtalk.enabled</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">开启钉钉消息通知。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>true</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.dingtalk.webhook-url</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">钉钉通知将要发送的webhook url。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.dingtalk.secret</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">消息认证的secret。</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring.boot.admin.notify.dingtalk.message</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">发送的文本，支持SpEL表达式。</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"#{instance.registration.name} #{instance.id} is #{event.statusInfo.status} "</code></p></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="securing-spring-boot-admin"><a class="anchor" href="#securing-spring-boot-admin"></a><a class="link" href="#securing-spring-boot-admin">5. 安全</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_保护sba服务端的安全"><a class="anchor" href="#_保护sba服务端的安全"></a><a class="link" href="#_保护sba服务端的安全">5.1. 保护SBA服务端的安全</a></h3>
<div class="paragraph">
<p>由于在分布式web应用中，有好几种可以解决身份认证和授权的方法，所以Spring Boot Admin没有默认为您选择它们中的哪一个。 默认情况下可以使用 <code>spring-boot-admin-server-ui</code> 来提供一个登录页面和注销按钮。</p>
</div>
<div class="paragraph">
<p>下面是一个针对Spring的安全配置示例:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Configuration</span>(proxyBeanMethods = <span class="predefined-constant">false</span>)
<span class="directive">public</span> <span class="type">class</span> <span class="class">SecuritySecureConfig</span> <span class="directive">extends</span> WebSecurityConfigurerAdapter {

  <span class="directive">private</span> <span class="directive">final</span> AdminServerProperties adminServer;

  <span class="directive">private</span> <span class="directive">final</span> SecurityProperties security;

  <span class="directive">public</span> SecuritySecureConfig(AdminServerProperties adminServer, SecurityProperties security) {
    <span class="local-variable">this</span>.adminServer = adminServer;
    <span class="local-variable">this</span>.security = security;
  }

  <span class="annotation">@Override</span>
  <span class="directive">protected</span> <span class="type">void</span> configure(HttpSecurity http) <span class="directive">throws</span> <span class="exception">Exception</span> {
    SavedRequestAwareAuthenticationSuccessHandler successHandler = <span class="keyword">new</span> SavedRequestAwareAuthenticationSuccessHandler();
    successHandler.setTargetUrlParameter(<span class="string"><span class="delimiter">&quot;</span><span class="content">redirectTo</span><span class="delimiter">&quot;</span></span>);
    successHandler.setDefaultTargetUrl(<span class="local-variable">this</span>.adminServer.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/</span><span class="delimiter">&quot;</span></span>));

    http.authorizeRequests(
        (authorizeRequests) -&gt; authorizeRequests.antMatchers(<span class="local-variable">this</span>.adminServer.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/assets/**</span><span class="delimiter">&quot;</span></span>)).permitAll() <i class="conum" data-value="1"></i><b>(1)</b>
            .antMatchers(<span class="local-variable">this</span>.adminServer.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/actuator/info</span><span class="delimiter">&quot;</span></span>)).permitAll()
            .antMatchers(<span class="local-variable">this</span>.adminServer.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/actuator/health</span><span class="delimiter">&quot;</span></span>)).permitAll()
            .antMatchers(<span class="local-variable">this</span>.adminServer.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/login</span><span class="delimiter">&quot;</span></span>)).permitAll().anyRequest().authenticated() <i class="conum" data-value="2"></i><b>(2)</b>
    ).formLogin(
        (formLogin) -&gt; formLogin.loginPage(<span class="local-variable">this</span>.adminServer.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/login</span><span class="delimiter">&quot;</span></span>)).successHandler(successHandler).and() <i class="conum" data-value="3"></i><b>(3)</b>
    ).logout((logout) -&gt; logout.logoutUrl(<span class="local-variable">this</span>.adminServer.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/logout</span><span class="delimiter">&quot;</span></span>))).httpBasic(<span class="predefined-type">Customizer</span>.withDefaults()) <i class="conum" data-value="4"></i><b>(4)</b>
        .csrf((csrf) -&gt; csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) <i class="conum" data-value="5"></i><b>(5)</b>
            .ignoringRequestMatchers(
                <span class="keyword">new</span> AntPathRequestMatcher(<span class="local-variable">this</span>.adminServer.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/instances</span><span class="delimiter">&quot;</span></span>),
                    HttpMethod.POST.toString()), <i class="conum" data-value="6"></i><b>(6)</b>
                <span class="keyword">new</span> AntPathRequestMatcher(<span class="local-variable">this</span>.adminServer.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/instances/*</span><span class="delimiter">&quot;</span></span>),
                    HttpMethod.DELETE.toString()), <i class="conum" data-value="6"></i><b>(6)</b>
                <span class="keyword">new</span> AntPathRequestMatcher(<span class="local-variable">this</span>.adminServer.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/actuator/**</span><span class="delimiter">&quot;</span></span>)) <i class="conum" data-value="7"></i><b>(7)</b>
            ))
        .rememberMe((rememberMe) -&gt; rememberMe.key(<span class="predefined-type">UUID</span>.randomUUID().toString()).tokenValiditySeconds(<span class="integer">1209600</span>));
  }

  <span class="comment">// Required to provide UserDetailsService for &quot;remember functionality&quot;</span>
  <span class="annotation">@Override</span>
  <span class="directive">protected</span> <span class="type">void</span> configure(AuthenticationManagerBuilder auth) <span class="directive">throws</span> <span class="exception">Exception</span> {
    auth.inMemoryAuthentication().withUser(security.getUser().getName())
        .password(<span class="string"><span class="delimiter">&quot;</span><span class="content">{noop}</span><span class="delimiter">&quot;</span></span> + security.getUser().getPassword()).roles(<span class="string"><span class="delimiter">&quot;</span><span class="content">USER</span><span class="delimiter">&quot;</span></span>);
  }

}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>对所有静态资源和登录页面进行放行处理。</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>其它所有请求都必须经过身份认证。</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>配置登录和注销逻辑。</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>开启HTTP-Basic认证。这是Spring Boot Admin客户端所需的。</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>启用Cookie的CSRF保护</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>禁用Spring Boot Admin客户端对于注册（注销）请求的CSRF保护</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td>禁用Spring Boot Admin客户端对于actuator接口的CSRF保护</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>如果使用Spring Boot Admin客户端，它还需要添加访问服务端的凭证:</p>
</div>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">spring.boot.admin.client</span>:
   <span class="key">username</span>: <span class="string"><span class="content">sba-client</span></span>
   <span class="key">password</span>: <span class="string"><span class="content">s3cret</span></span></code></pre>
</div>
</div>
<div class="paragraph">
<p>有关完整的示例，请查看 <a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-servlet/">spring-boot-admin-sample-servlet</a>。</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
如果你想要保护 <code>/instances</code> 接口，那么不要忘了在SBA客户端使用 <code>spring.boot.admin.client.username</code> 和 <code>spring.boot.admin.client.password</code> 配置用户名和密码。
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_保护客户端默认actuator接口"><a class="anchor" href="#_保护客户端默认actuator接口"></a><a class="link" href="#_保护客户端默认actuator接口">5.2. 保护客户端默认Actuator接口</a></h3>
<div class="paragraph">
<p>当actuator默认接口使用HTTP Basic身份认证进行安全保护时候，SBA就需要凭证才能访问它们了。 你可以在注册应用的时候在元数据中提交这个凭证。 之后 <code>BasicAuthHttpHeaderProvider</code> 就会使用元数据中提供的信息，在header中添加 <code>Authorization</code> 然后访问客户端应用的actuator接口了。 你也可以自定义一个 <code>HttpHeadersProvider</code> 来改变这个默认的行为（例如添加一些加密揭秘的逻辑）或者是在header中添加额外信息。</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
SBA服务端会屏蔽元数据中的一些信息，以防止敏感信息的泄漏。
</td>
</tr>
</table>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
在元数据提交身份凭证时，应该为SBA服务端（或者是服务发现）配置HTTPS。
</td>
</tr>
</table>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
使用Spring Cloud服务发现的时候，你必须随时注意，任何可以查询服务注册的人都可以看到你的认证信息。
</td>
</tr>
</table>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
使用这种方法SBA服务端就可以决定用户能否访问已注册的应用。 还有更加复杂的解决方案（使用OAuth2）来让客户端决定用户能否访问接口。 关于这一点，请参考 <a href="https://github.com/joshiste/spring-boot-admin-samples" target="_blank" rel="noopener">joshiste/spring-boot-admin-samples</a>。
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_sba客户端"><a class="anchor" href="#_sba客户端"></a><a class="link" href="#_sba客户端">5.2.1. SBA客户端</a></h4>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">spring.boot.admin.client</span>:
    <span class="key">url</span>: <span class="string"><span class="content">http://localhost:8080</span></span>
    <span class="key">instance</span>:
      <span class="key">metadata</span>:
        <span class="key">user.name</span>: <span class="string"><span class="content">${spring.security.user.name}</span></span>
        <span class="key">user.password</span>: <span class="string"><span class="content">${spring.security.user.password}</span></span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_sba服务端"><a class="anchor" href="#_sba服务端"></a><a class="link" href="#_sba服务端">5.2.2. SBA服务端</a></h4>
<div class="paragraph">
<p>你可以通过admin服务端的配置文件来指定凭证。</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
你可以将它与 <a href="https://cloud.spring.io/spring-cloud-kubernetes/1.1.x/reference/html/#secrets-propertysource" target="_blank" rel="noopener">spring-cloud-kubernetes</a> 结合起来一起使用，这样就能从 <a href="https://kubernetes.io/docs/concepts/configuration/secret/" target="_blank" rel="noopener">secrets</a> 中读取凭证了。
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>要想从配置文件读取凭证，需要将 <code>spring.boot.admin.instance-auth.enabled</code> 设置为 <code>true</code> （默认情况就是这样）。</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
如果客户端通过元数据提供了凭证（例如通过服务注解），那么元数据将会替换配置文件中的配置。
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>你可以通过使用 <code>spring.boot.admin.instance-auth.default-user-name</code> 和 <code>spring.boot.admin.instance-auth.default-user-password</code> 来提供默认的用户名和密码。 你也可以选择使用 <code>spring.boot.admin.instance-auth.service-map.*.user-name</code> 为指定名称的服务提供凭证，记得将 <code>*</code> 替换为服务名。</p>
</div>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">spring.boot.admin</span>:
  <span class="key">instance-auth</span>:
    <span class="key">enabled</span>: <span class="string"><span class="content">true</span></span>
    <span class="key">default-user-name</span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">${some.user.name.from.secret}</span><span class="delimiter">&quot;</span></span>
    <span class="key">default-password</span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">${some.user.password.from.secret}</span><span class="delimiter">&quot;</span></span>
    <span class="key">service-map</span>:
      <span class="key">my-first-service-to-monitor</span>:
        <span class="key">user-name</span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">${some.user.name.from.secret}</span><span class="delimiter">&quot;</span></span>
        <span class="key">user-password</span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">${some.user.password.from.secret}</span><span class="delimiter">&quot;</span></span>
      <span class="key">my-second-service-to-monitor</span>:
        <span class="key">user-name</span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">${some.user.name.from.secret}</span><span class="delimiter">&quot;</span></span>
        <span class="key">user-password</span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">${some.user.password.from.secret}</span><span class="delimiter">&quot;</span></span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_eureka"><a class="anchor" href="#_eureka"></a><a class="link" href="#_eureka">5.2.3. Eureka</a></h4>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">eureka</span>:
  <span class="key">instance</span>:
    <span class="key">metadata-map</span>:
      <span class="key">user.name</span>: <span class="string"><span class="content">${spring.security.user.name}</span></span>
      <span class="key">user.password</span>: <span class="string"><span class="content">${spring.security.user.password}</span></span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_consul"><a class="anchor" href="#_consul"></a><a class="link" href="#_consul">5.2.4. Consul</a></h4>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">spring.cloud.consul</span>:
  <span class="key">discovery</span>:
    <span class="key">metadata</span>:
        <span class="key">user-name</span>: <span class="string"><span class="content">${spring.security.user.name}</span></span>
        <span class="key">user-password</span>: <span class="string"><span class="content">${spring.security.user.password}</span></span></code></pre>
</div>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
Consul在元数据不允许使用点 (".") 作为key，应该使用减号（横杠）代理。
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_默认actuator接口的csrf保护"><a class="anchor" href="#_默认actuator接口的csrf保护"></a><a class="link" href="#_默认actuator接口的csrf保护">5.2.5. 默认Actuator接口的CSRF保护</a></h4>
<div class="paragraph">
<p>一些actuator接口 (例如 <code>/loggers</code>) 是支持POST请求的。
在使用Spring Security时需要禁用这些actuator接口的CSRF保护，因为Spring Boot Admin服务端目前缺乏对这方面的支持。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> configure(HttpSecurity http) <span class="directive">throws</span> <span class="exception">Exception</span> {
    http.csrf()
        .ignoringAntMatchers(<span class="string"><span class="delimiter">&quot;</span><span class="content">/actuator/**</span><span class="delimiter">&quot;</span></span>);
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_使用自定义tls"><a class="anchor" href="#_使用自定义tls"></a><a class="link" href="#_使用自定义tls">5.3. 使用自定义TLS</a></h3>
<div class="paragraph">
<p>SBA还可以在访问actuator接口的时候使用客户端证书进行身份认证。
在提供了 <code>ClientHttpConnector</code> bean时，Spring Boot就会用它自动配置 <code>WebClient.Builder</code>，之后供Spring Boot Admin使用。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Bean</span>
<span class="directive">public</span> ClientHttpConnector customHttpClient() {
    SslContextBuilder sslContext = SslContextBuilder.forClient();
    <span class="comment">//Your sslContext customizations go here</span>
    HttpClient httpClient = HttpClient.create().secure(
        ssl -&gt; ssl.sslContext(sslContext)
    );
    <span class="keyword">return</span> <span class="keyword">new</span> ReactorClientHttpConnector(httpClient);
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="customizing"><a class="anchor" href="#customizing"></a><a class="link" href="#customizing">6. 自定义</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="customizing-notifiers"><a class="anchor" href="#customizing-notifiers"></a><a class="link" href="#customizing-notifiers">6.1. 自定义通知器</a></h3>
<div class="paragraph">
<p>你可以实现 <code>Notifier</code> 接口，以Spring Beans的形式添加自己的通知程序，当然最好是继承 <code>AbstractEventNotifier</code> 或 <code>AbstractStatusChangeNotifier</code> 的方式。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">CustomNotifier</span> <span class="directive">extends</span> AbstractEventNotifier {

  <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">Logger</span> LOGGER = LoggerFactory.getLogger(LoggingNotifier.class);

  <span class="directive">public</span> CustomNotifier(InstanceRepository repository) {
    <span class="local-variable">super</span>(repository);
  }

  <span class="annotation">@Override</span>
  <span class="directive">protected</span> Mono&lt;<span class="predefined-type">Void</span>&gt; doNotify(InstanceEvent event, Instance instance) {
    <span class="keyword">return</span> Mono.fromRunnable(() -&gt; {
      <span class="keyword">if</span> (event <span class="keyword">instanceof</span> InstanceStatusChangedEvent) {
        LOGGER.info(<span class="string"><span class="delimiter">&quot;</span><span class="content">Instance {} ({}) is {}</span><span class="delimiter">&quot;</span></span>, instance.getRegistration().getName(), event.getInstance(),
            ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus());
      }
      <span class="keyword">else</span> {
        LOGGER.info(<span class="string"><span class="delimiter">&quot;</span><span class="content">Instance {} ({}) {}</span><span class="delimiter">&quot;</span></span>, instance.getRegistration().getName(), event.getInstance(),
            event.getType());
      }
    });
  }

}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="customizing-headers"><a class="anchor" href="#customizing-headers"></a><a class="link" href="#customizing-headers">6.2. 自定义HTTP请求头</a></h3>
<div class="paragraph">
<p>为了监控应用而发送的actuator接口，如果你需要在其中添加自定义HTTP请求头的话，可以使用 <code>HttpHeadersProvider</code> 来轻松的实现:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Bean</span>
<span class="directive">public</span> HttpHeadersProvider customHttpHeadersProvider() {
  <span class="keyword">return</span> (instance) -&gt; {
    HttpHeaders httpHeaders = <span class="keyword">new</span> HttpHeaders();
    httpHeaders.add(<span class="string"><span class="delimiter">&quot;</span><span class="content">X-CUSTOM</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">My Custom Value</span><span class="delimiter">&quot;</span></span>);
    <span class="keyword">return</span> httpHeaders;
  };
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="customizing-instance-filter"><a class="anchor" href="#customizing-instance-filter"></a><a class="link" href="#customizing-instance-filter">6.3. 对请求和响应进行拦截</a></h3>
<div class="paragraph">
<p>为了监控应用而发送的actuator接口，如果你需要拦截并修改其请求以及响应的话，可以通过实现 <code>InstanceExchangeFilterFunction</code> 来完成。 这对审核或者是添加额外的安全检查很有作用。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Bean</span>
<span class="directive">public</span> InstanceExchangeFilterFunction auditLog() {
  <span class="keyword">return</span> (instance, request, next) -&gt; next.exchange(request).doOnSubscribe((s) -&gt; {
    <span class="keyword">if</span> (HttpMethod.DELETE.equals(request.method()) || HttpMethod.POST.equals(request.method())) {
      log.info(<span class="string"><span class="delimiter">&quot;</span><span class="content">{} for {} on {}</span><span class="delimiter">&quot;</span></span>, request.method(), instance.getId(), request.url());
    }
  });
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="customizing-external-views"><a class="anchor" href="#customizing-external-views"></a><a class="link" href="#customizing-external-views">6.4. 链接/嵌入外部页面</a></h3>
<div class="paragraph">
<p>你可以非常简单的通过配置添加一个外部页面的链接甚至是直接将他们嵌入进来 (添加 <code>iframe=true</code> 参数)。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">spring</span>:
  <span class="key">boot</span>:
    <span class="key">admin</span>:
      <span class="key">ui</span>:
        <span class="key">external-views</span>:
          - <span class="string"><span class="content">label: &quot;🚀&quot;</span></span>
            <span class="key">url</span>: <span class="string"><span class="content">http://codecentric.de</span></span>
            <span class="key">order</span>: <span class="string"><span class="content">2000</span></span></code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="customizing-custom-views"><a class="anchor" href="#customizing-custom-views"></a><a class="link" href="#customizing-custom-views">6.5. 自定义页面</a></h3>
<div class="paragraph">
<p>您也可以向前端添加自定义页面。页面必须是一个 <a href="https://vuejs.org/">Vue.js</a> 组件。</p>
</div>
<div class="paragraph">
<p>js文件还有css样式表必须放在classpath下的 <code>/META-INF/spring-boot-admin-server-ui/extensions/{name}/</code> 路径，这样服务端才能拿到它们。
<a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-custom-ui/">spring-boot-admin-sample-custom-ui</a> 模块中包含了一个示例，该示例展示了如何配置maven来成功的构建一个模块。</p>
</div>
<div class="paragraph">
<p>要想自定义拓展将自己注册，可以调用 <code>SBA.use()</code> 然后还需要暴露 <code>install()</code> 函数，这在配置路由参数的时候会被ui调用。
<code>install()</code> 函数在注册页面和/或是回调时接收以下参数:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-server-ui/src/main/frontend/viewRegistry.js">viewRegistry</a> 的对象引用</p>
</li>
<li>
<p><a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-server-ui/src/main/frontend/store.js">applicationStore</a> 的对象引用</p>
</li>
<li>
<p>the global Vue[Vue] 的对象引用</p>
</li>
<li>
<p><a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-server-ui/src/main/frontend/utils/axios.js">axios</a> 的对象引用</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>如果前端添加了顶级路由，那么后端也必须知道。 可以在 <code>/META-INF/spring-boot-admin-server-ui/extensions/{name}/routes.txt</code> 文件配置所有的顶级路由，每个路由占一行。</p>
</div>
<div class="sect3">
<h4 id="customizing-custom-views-top-level"><a class="anchor" href="#customizing-custom-views-top-level"></a><a class="link" href="#customizing-custom-views-top-level">6.5.1. 添加顶级页面</a></h4>
<div class="paragraph">
<p>下面是一个简单的顶级页面示例，其中列表出所有已注册的应用:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="html"><span class="tag">&lt;template&gt;</span>
  <span class="tag">&lt;pre</span> <span class="attribute-name">v-text</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">stringify(applications, null, 4)</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span>
<span class="tag">&lt;/template&gt;</span>

<span class="tag">&lt;script&gt;</span>
<span class="inline"><span class="reserved">export</span> <span class="keyword">default</span> {
  <span class="key">props</span>: {
    <span class="key">applications</span>: { <i class="conum" data-value="1"></i><b>(1)</b>
      <span class="key">type</span>: Array,
      <span class="key">required</span>: <span class="predefined-constant">true</span>
    }
  },
  <span class="key">methods</span>: {
    <span class="key">stringify</span>: JSON.stringify
  }
};</span>
<span class="tag">&lt;/script&gt;</span></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>如果你在组件中定义了 <code>applications</code> 属性，组件会将所有已注册的应用注入进来。</td>
</tr>
</table>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
应用中还提供了一些很有用的方法和可用的实例对象。可以参考 <a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-server-ui/src/main/frontend/services/application.js">application.js</a> 以及 <a href="https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-server-ui/src/main/frontend/services/instance.js">instance.js</a>。
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>这里展示了如何注册顶级试图。</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="javascript">SBA.use({
  install({viewRegistry}) {
    viewRegistry.addView({
      <span class="key">name</span>: <span class="string"><span class="delimiter">'</span><span class="content">custom</span><span class="delimiter">'</span></span>,  <i class="conum" data-value="1"></i><b>(1)</b>
      <span class="key">path</span>: <span class="string"><span class="delimiter">'</span><span class="content">/custom</span><span class="delimiter">'</span></span>, <i class="conum" data-value="2"></i><b>(2)</b>
      <span class="key">component</span>: custom, <i class="conum" data-value="3"></i><b>(3)</b>
      <span class="key">label</span>: <span class="string"><span class="delimiter">'</span><span class="content">Custom</span><span class="delimiter">'</span></span>, <i class="conum" data-value="4"></i><b>(4)</b>
      <span class="key">order</span>: <span class="integer">1000</span>, <i class="conum" data-value="5"></i><b>(5)</b>
    });
  }
});</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>试图以及路由名称</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>试图的访问路径</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>引用的自定义组件，将会在路由上渲染</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>在顶部导航栏显示自定义试图的label</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>对试图进行排序。顶部导航栏中的试图是按照升序进行排序的。</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>添加了路由的 <code>routes.txt</code> 文件:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="text">/custom/**</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="customizing-custom-views-instance"><a class="anchor" href="#customizing-custom-views-instance"></a><a class="link" href="#customizing-custom-views-instance">6.5.2. 查看自定义接口</a></h4>
<div class="paragraph">
<p>下面是调用自定义接口的试图:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="html"><span class="tag">&lt;template&gt;</span>
  <span class="tag">&lt;div</span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">custom</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
    <span class="tag">&lt;p&gt;</span>Instance: <span class="tag">&lt;span</span> <span class="attribute-name">v-text</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">instance.id</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span><span class="tag">&lt;/p&gt;</span>
    <span class="tag">&lt;p&gt;</span>Output: <span class="tag">&lt;span</span> <span class="attribute-name">v-text</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">text</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span><span class="tag">&lt;/p&gt;</span>
  <span class="tag">&lt;/div&gt;</span>
<span class="tag">&lt;/template&gt;</span>

<span class="tag">&lt;script&gt;</span>
<span class="inline">  <span class="reserved">export</span> <span class="keyword">default</span> {
    <span class="key">props</span>: {
      <span class="key">instance</span>: { <i class="conum" data-value="1"></i><b>(1)</b>
        <span class="key">type</span>: Object,
        <span class="key">required</span>: <span class="predefined-constant">true</span>
      }
    },
    <span class="key">data</span>: () =&gt; ({
      <span class="key">text</span>: <span class="string"><span class="delimiter">'</span><span class="delimiter">'</span></span>
    }),
    async created() {
      const response = await <span class="local-variable">this</span>.instance.axios.get(<span class="string"><span class="delimiter">'</span><span class="content">actuator/custom</span><span class="delimiter">'</span></span>); <i class="conum" data-value="2"></i><b>(2)</b>
      <span class="local-variable">this</span>.text = response.data;
    }
  };</span>
<span class="tag">&lt;/script&gt;</span>

<span class="tag">&lt;style&gt;</span>
<span class="inline">  <span class="class">.custom</span> {
    <span class="key">font-size</span>: <span class="float">20px</span>;
    <span class="key">width</span>: <span class="float">80%</span>;
  }</span>
<span class="tag">&lt;/style&gt;</span></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>如果你在组件中定义了 <code>instance</code> 属性，组件会将需要渲染的对象注入进来。</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>所有的实例中都提前配置好了 <a href="https://github.com/axios/axios">axios</a> 供您访问，您只需要输入正确的路径和请求头就好了。</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>注册实例的工作方式与顶级试图差不多，但有一些额外的附加属性:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="javascript">SBA.use({
  install({viewRegistry, vueI18n}) {
    viewRegistry.addView({
      <span class="key">name</span>: <span class="string"><span class="delimiter">'</span><span class="content">instances/custom</span><span class="delimiter">'</span></span>,
      <span class="key">parent</span>: <span class="string"><span class="delimiter">'</span><span class="content">instances</span><span class="delimiter">'</span></span>, <i class="conum" data-value="1"></i><b>(1)</b>
      <span class="key">path</span>: <span class="string"><span class="delimiter">'</span><span class="content">custom</span><span class="delimiter">'</span></span>,
      <span class="key">component</span>: customEndpoint,
      <span class="key">label</span>: <span class="string"><span class="delimiter">'</span><span class="content">Custom</span><span class="delimiter">'</span></span>,
      <span class="key">group</span>: <span class="string"><span class="delimiter">'</span><span class="content">custom</span><span class="delimiter">'</span></span>, <i class="conum" data-value="2"></i><b>(2)</b>
      <span class="key">order</span>: <span class="integer">1000</span>,
      <span class="key">isEnabled</span>: ({instance}) =&gt; instance.hasEndpoint(<span class="string"><span class="delimiter">'</span><span class="content">custom</span><span class="delimiter">'</span></span>) <i class="conum" data-value="3"></i><b>(3)</b>
    });

    vueI18n.mergeLocaleMessage(<span class="string"><span class="delimiter">'</span><span class="content">en</span><span class="delimiter">'</span></span>, { <i class="conum" data-value="4"></i><b>(4)</b>
      <span class="key">sidebar</span>: {
        <span class="key">custom</span> : {
          <span class="key">title</span> : <span class="string"><span class="delimiter">&quot;</span><span class="content">My Custom Extensions</span><span class="delimiter">&quot;</span></span>
        }
      }
    });
  }
});</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>这里的parent必须是 'instances' ，这样才能为单例提供新的自定义试图。</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>可以对试图进行分组。</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>如果添加了 <code>isEnabled</code> 选项，则可以动态判断是否为特定实例显示试图。</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>注册自定义i18n翻译</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
你可以以同分组、同名试图的方式对默认试图进行覆盖。
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_自定义顶部logo和标题"><a class="anchor" href="#_自定义顶部logo和标题"></a><a class="link" href="#_自定义顶部logo和标题">6.6. 自定义顶部Logo和标题</a></h3>
<div class="paragraph">
<p>你可以使用下列属性对标题中的信息（例如显示登录信息或者是公司名称）进行自定义:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>spring.boot.admin.ui.brand</strong>: 这段HTML会渲染到导航标题中，默认是 <code>&lt;img src="assets/img/icon-spring-boot-admin.svg"&gt;&lt;span&gt;Spring Boot Admin&lt;/span&gt;</code>。
默认情况下这里会显示SBA的logo，后面加上名称。
你可以在 <code>/META-INF/spring-boot-admin-server-ui/</code> 这个路径（SBA默认会从这个路径下注册 <code>ResourceHandler</code> ）下添加图片，或者用其它方式确保正确的提供图片（比如手动注册 <code>ResourceHandler</code> ）。</p>
</li>
<li>
<p><strong>spring.boot.admin.ui.title</strong>: 使用这个选项可以自定义浏览器窗口标题。</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_自定义登录logo"><a class="anchor" href="#_自定义登录logo"></a><a class="link" href="#_自定义登录logo">6.7. 自定义登录Logo</a></h3>
<div class="paragraph">
<p>你可以自定义登录页面的图片。</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>将图片放在http可以访问到的资源目录下（例如 <code>/META-INF/spring-boot-admin-server-ui/assets/img/</code>）。</p>
</li>
<li>
<p>使用下面的属性来配置要使用的图标:</p>
<div class="ulist">
<ul>
<li>
<p><strong>spring.boot.admin.ui.login-icon</strong>: 用作登录页面上的图标(例 <code>assets/img/custom-login-icon.svg</code>)。</p>
</li>
</ul>
</div>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="_自定义favicon"><a class="anchor" href="#_自定义favicon"></a><a class="link" href="#_自定义favicon">6.8. 自定义Favicon</a></h3>
<div class="paragraph">
<p>可以使用自定义的favicon，它也会用在桌面通知上。
当有一个或多个应用关闭时，Spring Boot Admin会使用不同的图标。</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>将favicon图标（<code>.png</code> 格式，最低192x192像素）放在http可以访问到的资源目录下（例如 <code>/META-INF/spring-boot-admin-server-ui/assets/img/</code>）。</p>
</li>
<li>
<p>下面的属性可以配置要使用的图标:</p>
<div class="ulist">
<ul>
<li>
<p><code>spring.boot.admin.ui.favicon</code>: 配置默认图标(例 <code>assets/img/custom-favicon.png</code>) 。</p>
</li>
<li>
<p><code>spring.boot.admin.ui.favicon-danger</code>: 在一个或多个服务关闭时使用这个图标 (例 <code>assets/img/custom-favicon-danger.png</code>)。</p>
</li>
</ul>
</div>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="_自定义可用语言"><a class="anchor" href="#_自定义可用语言"></a><a class="link" href="#_自定义可用语言">6.9. 自定义可用语言</a></h3>
<div class="paragraph">
<p>要想筛选所有支持的语言，可以使用下面的选项:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>spring.boot.admin.ui.available-languages</strong>: 配置现有语言的过滤器 (例如 <code>en,de</code> out of existing <code>de,en,fr,ko,pt-BR,ru,zh</code>)。</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_显示隐藏页面"><a class="anchor" href="#_显示隐藏页面"></a><a class="link" href="#_显示隐藏页面">6.10. 显示/隐藏页面</a></h3>
<div class="paragraph">
<p>要想在导航栏中隐藏试图，可以很简单的实现：</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yaml"><span class="key">spring</span>:
  <span class="key">boot</span>:
    <span class="key">admin</span>:
      <span class="key">ui</span>:
        <span class="key">view-settings</span>:
          - <span class="string"><span class="content">name: &quot;journal&quot;</span></span>
            <span class="key">enabled</span>: <span class="string"><span class="content">false</span></span></code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="monitoring-spring-boot-1.5.x"><a class="anchor" href="#monitoring-spring-boot-1.5.x"></a><a class="link" href="#monitoring-spring-boot-1.5.x">7. 监听1.5.x版本的Spring Boot</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>使用 Spring Boot Admin 2.x 也可以监控 Spring Boot 1.5.x 版本的应用。
旧版本的Spring Boot Admin客户端可以注册到新版本的服务端上。
由于API有一些细微的变化，你可以在旧版本的客户端上添加下面的配置:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>为 Spring Boot Admin 客户端1.5.x版本重新配置api路径:</p>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="yml"><span class="key">spring.boot.admin.api-path</span>: <span class="string"><span class="content">instances</span></span></code></pre>
</div>
</div>
</li>
</ol>
</div>
<div class="paragraph">
<p>由于Spring Boot 2版本中，一些actuator接口发生了变化，并非所有选项都可用（比如 <code>/metrics</code> 接口）；
对于这些接口，我们也提供了遗留接口的转换器。</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_2_x版本的变化"><a class="anchor" href="#_2_x版本的变化"></a><a class="link" href="#_2_x版本的变化">8. 2.x版本的变化</a></h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Added stable automatic-module-name to all jars</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_页面"><a class="anchor" href="#_页面"></a><a class="link" href="#_页面">8.1. 页面</a></h3>
<div class="ulist">
<ul>
<li>
<p>使用vue.js重写了ui页面</p>
</li>
<li>
<p>将登录页面模块集成到主模块中</p>
</li>
<li>
<p>删除了活动模块，因为没什么人使用它</p>
</li>
<li>
<p>移除了Hystrix-Dashboard的集成（可能会改变）</p>
</li>
<li>
<p>添加了session接口</p>
</li>
<li>
<p>添加了元数据（屏蔽之后）的显示</p>
</li>
<li>
<p>添加了重置日志级别的选项</p>
</li>
<li>
<p>添加了 wallboard 试图</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_后端"><a class="anchor" href="#_后端"></a><a class="link" href="#_后端">8.2. 后端</a></h3>
<div class="ulist">
<ul>
<li>
<p>将所有的类都移动到了 <code>spring.boot.admin.server</code> 包下</p>
</li>
<li>
<p>与Spring cloud相关的拓展移动到了 <code>spring-boot-admin-server-cloud</code></p>
</li>
<li>
<p>使用event sourcing 原则对后端重新进行了设计</p>
</li>
<li>
<p>添加了应用的概念（有1到n个实例组成）</p>
</li>
<li>
<p>将检测接口移动到后端，通过 <code>/actuator</code> 地址发送OPTIONS请求进行索引或者是查看</p>
</li>
<li>
<p>使用WebClient自定义代理代替Zuul</p>
</li>
<li>
<p>移除spring-cloud-starter依赖</p>
</li>
<li>
<p>添加了 <code>CompositeHttpHeadersProvider</code> 来适配同时有多个 <code>HttpHeadersProviders</code> 的情况</p>
</li>
<li>
<p>添加了 <code>InstanceExchangeFilterFunctions</code> ，它允许对向被监控的实例所发出的请求进行拦截/修改</p>
</li>
<li>
<p>添加了CloudFoundry开箱即用的支持</p>
</li>
<li>
<p>添加了使用 <code>LegacyEndpointConverters</code> 对 Spring Boot 1.5.x 版本actuator接口的支持</p>
</li>
<li>
<p>更新 <code>OpsGenieNotifier</code> 的api到v2版本</p>
</li>
<li>
<p>使用Thymeleaf模板重写了 <code>MailNotifier</code></p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_客户端"><a class="anchor" href="#_客户端"></a><a class="link" href="#_客户端">8.3. 客户端</a></h3>
<div class="ulist">
<ul>
<li>
<p>将所有的配置移动到 <code>spring.boot.admin.client.<strong></code> 以及 <code>spring.boot.admin.client.instance.</strong></code> 下</p>
</li>
<li>
<p>将所有源码移动到 <code>spring.boot.admin.client</code> 包下</p>
</li>
<li>
<p>添加了对webflux应用的支持</p>
</li>
<li>
<p>添加了CloudFoundry开箱即用的支持</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="faqs"><a class="anchor" href="#faqs"></a><a class="link" href="#faqs">9. 常见问题</a></h2>
<div class="sectionbody">
<div class="dlist q-and-a">
<dl>
<dt>我可以在我的业务系统应用中添加spring-boot-admin吗？</dt>
<dd>
<p><strong>tl;dr</strong> 可以，但是不应该这么做。<br>
你可以设置 <code>spring.boot.admin.context-path</code> 改变UI以及REST-API的访问路径，但是基于应用的业务复杂度，你还是有可能遇到一些问题。
另一方面，在我看来一个应用自己监控自己是没有意义的。如果你的应用挂掉了，那么监控它的工具也就同时挂掉了。</p>
</dd>
</dl>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Version 2.6.6<br>
</div>
</div>
</body>
</html>